From 9c95bed67e49edd16f956f031465b81ec35a7ed3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 6 Jan 2021 11:59:47 +0100 Subject: [PATCH] Generic DRC: new tests, bug fixes. --- src/db/db/dbCompoundOperation.cc | 16 ++++++- src/db/db/dbCompoundOperation.h | 7 ++- src/db/db/gsiDeclDbCompoundOperation.cc | 34 +++++++++------ src/db/unit_tests/dbCompoundOperationTests.cc | 11 ++++- .../drc/built-in-macros/_drc_complex_ops.rb | 9 +++- .../built-in-macros/_drc_cop_integration.rb | 14 +++--- src/drc/drc/built-in-macros/_drc_engine.rb | 4 +- src/drc/unit_tests/drcGenericTests.cc | 10 +++++ testdata/drc/compound_au1.gds | Bin 918 -> 1026 bytes testdata/drc/compound_au1d.gds | Bin 918 -> 1026 bytes testdata/drc/drcGenericTests_2.drc | 41 ++++++++++++++++++ testdata/drc/drcGenericTests_2.gds | Bin 0 -> 1118 bytes testdata/drc/drcGenericTests_au2.gds | Bin 0 -> 3626 bytes testdata/drc/drcGenericTests_au2d.gds | Bin 0 -> 3358 bytes 14 files changed, 115 insertions(+), 31 deletions(-) create mode 100644 testdata/drc/drcGenericTests_2.drc create mode 100644 testdata/drc/drcGenericTests_2.gds create mode 100644 testdata/drc/drcGenericTests_au2.gds create mode 100644 testdata/drc/drcGenericTests_au2d.gds diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index f5bc28f04..8a0197dc1 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -1486,6 +1486,18 @@ CompoundRegionEdgePairToEdgeProcessingOperationNode::do_compute_local (db::Layou // --------------------------------------------------------------------------------------------- +CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options) + : CompoundRegionMultiInputOperationNode (), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options) +{ + set_description ("check"); + + m_check.set_include_zero (false); + m_check.set_whole_edges (options.whole_edges); + m_check.set_ignore_angle (options.ignore_angle); + m_check.set_min_projection (options.min_projection); + m_check.set_max_projection (options.max_projection); +} + CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode *input, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options) : CompoundRegionMultiInputOperationNode (input), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options) { @@ -1498,8 +1510,8 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi m_check.set_max_projection (options.max_projection); } -CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options) - : CompoundRegionMultiInputOperationNode (), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options) +CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode * /*input*/, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options) + : CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options) { set_description ("check"); diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 8b7801ead..6aa9e90df 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -1387,7 +1387,12 @@ public: CompoundRegionCheckOperationNode (db::CompoundRegionOperationNode *input, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options); /** - * @brief Constructor for the single-layer check + * @brief Constructor for the two-layer check + */ + CompoundRegionCheckOperationNode (db::CompoundRegionOperationNode *input, db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options); + + /** + * @brief Constructor for a single-polygon check (width, notch) */ CompoundRegionCheckOperationNode (db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options); diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index e5f0fa4a0..5faf6688b 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -56,6 +56,11 @@ static db::CompoundRegionOperationNode *new_primary () return new db::CompoundRegionOperationPrimaryNode (); } +static db::CompoundRegionOperationNode *new_foreign () +{ + return new db::CompoundRegionOperationForeignNode (); +} + static db::CompoundRegionOperationNode *new_secondary (db::Region *region) { check_non_null (region, "region"); @@ -372,7 +377,7 @@ static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::Compo static db::CompoundRegionOperationNode *new_check_node (db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) { - return new db::CompoundRegionCheckOperationNode (rel, different_polygons, d, + return new db::CompoundRegionCheckOperationNode (new_primary (), rel, different_polygons, d, db::RegionCheckOptions (whole_edges, metrics, ignore_angle.is_nil () ? 90 : ignore_angle.to_double (), @@ -385,10 +390,10 @@ static db::CompoundRegionOperationNode *new_check_node (db::edge_relation_type r ); } -static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *input, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) +static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) { - check_non_null (input, "input"); - return new db::CompoundRegionCheckOperationNode (input, rel, different_polygons, d, + check_non_null (other, "other"); + return new db::CompoundRegionCheckOperationNode (new_primary (), other, rel, different_polygons, d, db::RegionCheckOptions (whole_edges, metrics, ignore_angle.is_nil () ? 90 : ignore_angle.to_double (), @@ -435,19 +440,19 @@ static db::CompoundRegionOperationNode *new_notch_check (db::Coord d, bool whole return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::SinglePolygonCheck (db::SpaceRelation, d, options), new_primary (), true /*processor is owned*/); } -static db::CompoundRegionOperationNode *new_separation_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) +static db::CompoundRegionOperationNode *new_separation_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) { - return new_check_node (input, db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); + return new_check_node (other, db::SpaceRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); } -static db::CompoundRegionOperationNode *new_overlap_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) +static db::CompoundRegionOperationNode *new_overlap_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) { - return new_check_node (input, db::OverlapRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); + return new_check_node (other, db::OverlapRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); } -static db::CompoundRegionOperationNode *new_inside_check (db::CompoundRegionOperationNode *input, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) +static db::CompoundRegionOperationNode *new_inside_check (db::CompoundRegionOperationNode *other, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative) { - return new_check_node (input, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); + return new_check_node (other, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded, opposite_filter, rect_filter, negative); } static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits::perimeter_type pmin, db::coord_traits::perimeter_type pmax) @@ -502,6 +507,9 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_primary", &new_primary, "@brief Creates a node object representing the primary input" ) + + gsi::constructor ("new_foreign", &new_foreign, + "@brief Creates a node object representing the primary input without the current polygon" + ) + gsi::constructor ("new_secondary", &new_secondary, gsi::arg ("region"), "@brief Creates a node object representing the secondary input from the given region" ) + @@ -620,13 +628,13 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_notch_check", &new_notch_check, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("negative", false), "@brief Creates a node providing a intra-polygon space check.\n" ) + - gsi::constructor ("new_separation_check", &new_separation_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), + gsi::constructor ("new_separation_check", &new_separation_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), "@brief Creates a node providing a separation check.\n" ) + - gsi::constructor ("new_overlap_check", &new_overlap_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), + gsi::constructor ("new_overlap_check", &new_overlap_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), "@brief Creates a node providing an overlap check.\n" ) + - gsi::constructor ("new_inside_check", &new_inside_check, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), + gsi::constructor ("new_inside_check", &new_inside_check, gsi::arg ("other"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max."), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoSideAllowed, "NoSideAllowed"), gsi::arg ("negative", false), "@brief Creates a node providing an inside (enclosure) check.\n" ) + gsi::constructor ("new_perimeter_filter", &new_perimeter_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits::perimeter_type>::max (), "max"), diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc index 281b793ad..c37786e1c 100644 --- a/src/db/unit_tests/dbCompoundOperationTests.cc +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -84,9 +84,9 @@ void run_test1 (tl::TestBase *_this, bool deep) res.insert_into (&ly, *ly.begin_top_down (), l1000); db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode (); - db::CompoundRegionCheckOperationNode space_check (primary, db::SpaceRelation, true /*==different polygons*/, 1050, check_options); + db::CompoundRegionCheckOperationNode isolation_check (primary, db::SpaceRelation, true /*==different polygons*/, 1050, check_options); - res = r.cop_to_edge_pairs (space_check); + res = r.cop_to_edge_pairs (isolation_check); unsigned int l1001 = ly.get_layer (db::LayerProperties (1001, 0)); res.insert_into (&ly, *ly.begin_top_down (), l1001); @@ -99,6 +99,13 @@ void run_test1 (tl::TestBase *_this, bool deep) unsigned int l1002 = ly.get_layer (db::LayerProperties (1002, 0)); res.insert_into (&ly, *ly.begin_top_down (), l1002); + db::CompoundRegionCheckOperationNode space_check (primary, db::SpaceRelation, false /*==all polygons*/, 1050, check_options); + + res = r.cop_to_edge_pairs (space_check); + + unsigned int l1003 = ly.get_layer (db::LayerProperties (1003, 0)); + res.insert_into (&ly, *ly.begin_top_down (), l1003); + CHECKPOINT(); db::compare_layouts (_this, ly, make_au ("1", deep)); } diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index adf7b579f..40e85452a 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -1495,16 +1495,21 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare :isolated => :new_isolated_check, :overlap => :new_overlap_check, :enclosing => :new_inside_check }[self.check] + oargs = [] + if self.other + oargs << self.other.create_node(cache) + end + if self.lt || self.le dmin = self.le ? @engine._make_value(self.le) + 1 : @engine._make_value(self.lt) - res = RBA::CompoundRegionOperationNode::send(factory, dmin, *self.args) + res = RBA::CompoundRegionOperationNode::send(factory, *(oargs + [ dmin ] + self.args)) else res = nil end if self.gt || self.ge dmax = self.ge ? @engine._make_value(self.ge) : @engine._make_value(self.gt) + 1 - max_check = RBA::CompoundRegionOperationNode::send(factory, dmax, *self.args + [ true ]) + max_check = RBA::CompoundRegionOperationNode::send(factory, *(oargs + [ dmax ] + self.args + [ true ])) if res if self.check == :width || self.check == :notch # Same polygon check - we need to take both edges of the result diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb index f9f233857..58d6a25be 100644 --- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb +++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb @@ -206,9 +206,9 @@ module DRC # out = in.drc(primary & foreign.sized(0.5.um)) # @/code - def primary - res = DRCOpNode::new(self, RBA::CompoundRegionOperationNode::new_primary) - res.description = "primary" + def foreign + res = DRCOpNode::new(self, RBA::CompoundRegionOperationNode::new_foreign) + res.description = "foreign" return res end @@ -773,13 +773,9 @@ CODE end if :#{f} == :width || :#{f} == :space || :#{f} == :notch || :#{f} == :isolated - if other - raise("No other layer must be specified for a single-layer check") - end + other && raise("No other layer must be specified for a single-layer check") else - if !other - raise("The other layer must be specified for a two-layer check") - end + other || raise("The other layer must be specified for a two-layer check") end DRCOpNodeCheck::new(self, :#{f}, other, *args) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index b65a55bc7..94c8512eb 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1523,7 +1523,7 @@ CODE %w( enc enclosing - overlapping + overlap sep separation ).each do |f| @@ -1595,7 +1595,7 @@ CODE output outside outside_part - overlap + overlapping perimeter pull_inside pull_interacting diff --git a/src/drc/unit_tests/drcGenericTests.cc b/src/drc/unit_tests/drcGenericTests.cc index 41b416b4e..6ca4b97b4 100644 --- a/src/drc/unit_tests/drcGenericTests.cc +++ b/src/drc/unit_tests/drcGenericTests.cc @@ -78,3 +78,13 @@ TEST(1d) { runTest (_this, "1", true); } + +TEST(2) +{ + runTest (_this, "2", false); +} + +TEST(2d) +{ + runTest (_this, "2", true); +} diff --git a/testdata/drc/compound_au1.gds b/testdata/drc/compound_au1.gds index 9136405aea0e2c98c7de16967a6160759a00a516..9e74ff55dd7c4f1023974d33566badfed6c49be9 100644 GIT binary patch delta 156 zcmbQn-oz2bz{bGD6u}_F$i)7Xff2~#X5eBFMrJc`FtPb~Ix#SaFtge@cA9%1TmHe) zWrzNP*-;@3GORfDO^gZ@$6@5gL+6+{I2jn&c$t`APd>n8$_OGQCi5|iv9U8Su&^)y E0HgmJQ~&?~ delta 133 zcmZqTn8qH(z{bGD6u}_F$i)7Hfrmkofses}!5Ep%z`?}kn8$_OGQCi5|iv9U8Su&^)y E0NBYJ0ssI2 delta 133 zcmZqTn8qH(z{bGD6u}_F$i)7HfrmkgL4-kzK^2+Jz`?}kjtvbB4fPpX+-hiS@B>71 zAE2>7B0?f08akbG-wwXzpYGuAa?bmlb3D&`Vc>at$Va@`6CyB30GM{)5%)~3S^^gQ z=w|VJef#dRw^8n_wlDS@$VVsWjHwrQ8wlcnNqJIz#^dTMvp)Yi&*CxQcLAl73g&x+5nGKJbwI?h7{bXfk z7f!cA_<7T8dc|>eF@(K&GokF$D>i(l!2j{kY-TA05FY<0lznEY#5WuL6vA%D@z)iz zQ|loJWsg|&|NFe_2WJ<}THg|)-`7ig_J{C&)e(RA7s?*7=zo6#eh47BGfOCYnNQqi zEcnM?`o(kV#xG1OO?;1Ed&wU^<%M|4`aQqw(K+l-_<4Y`$B%;k z5Wc+k{DHe2>L?-k^Yt`nT&HpqVn;MAJuLMVGV|6cdRN&QoA)Q(X0 zruc~$o$%QY-%<9ireglMZ|v7SrUvn^TJ-f={;K@`Z*7FIvq1dZyAZaQ6Ux4`P~w}7 zd^S7r!I8Qpvl9ad5`KQvO^YzW$|O_J}!uG4WH~sE=~~^i9=~*HxLH>c!($9jGpRz06mgfb?ze zqv>AzdX4|6Nk4v%&|l+oZ~weW@rs}HvtIV!hyKS+`u`*UOHF*~Z#cgiUwupa#n0o9 zG3NDC@#fe-HoI`ZIoC`d0_k-@`w) z{*2$3{$~T~@8KU?f5z`i|BGCIUhnFg!gL>M^j`L0_! YrCTU_kN(X6VSc)KIx2so@f?TkFD4f25T4t++q)zeqfrTwD=icR(}@s-#1shz40457S)>dayA&3p2`E@=AxJtc zEK}qM1Z#hQl_&&}5Q2mtlIQz&?sMmDZugSS7WW5u|&~*X;-4g52;8j zLvmHF*#FXu;`zC0kqg!Ot*KWx?tK2Rdvj*<`ue*E9ckAKcyYWib+03}rbs*-;p=B2 z5xI7@>VM61@u^64TZCwqYUf014Jq_97{|9~=jLbpn}Z_FQT5s~UXrgIU32c|s`OZM z?$6~!L$cOOeRVtGdezSDbwoziQ}o|V?ELmozH^5y@D&dx;LAB8?fHC>#ut&HO~vys zMTS3#5NY>l^+z`P^{*lWTOvS2ePlgF+C3KVo%{X~eCKu_!hedidrbI!ve%5`&fNvg z-QXxQ*(-bLYJ92kOr+JWPjC3p;qmWl2K;}k+MGG(e$Qf;isOqKaU$(L8oB(PC6TdZ z=YZhhdqmpDmhIx>bVDeg}?_iF_@ z6lwR_wEnB%slmIwvrfB5%U?|S8aL=<9IMf7j}ianBK|SwCbL$^9I=! z&-j0FO8psrsuO+h82Syrl>XII>d){`tl#iU>0djg{tW-b`VGI7{?}GN?j4?c_H82V znfoW;m#F`MZ~G7X4l$?yyh-(^_b#R`Xkpz0F@<%fF