From 390d56601a31afa2e87b2d11d5ad4aa47a4a90ba Mon Sep 17 00:00:00 2001 From: Vadim Kurland Date: Thu, 7 Apr 2011 20:55:53 -0700 Subject: [PATCH] * PIXImporterNat.cpp (buildDNATRule): resolved several problems with import of "static" commands that use access list that matches source or destination tcp/udp ports. See #2326, #2327 --- doc/ChangeLog | 4 + src/import/PIXImporter.cpp | 40 +- src/import/PIXImporterNat.cpp | 22 +- src/import/serviceObjectMaker.cpp | 47 ++ src/import/serviceObjectMaker.h | 3 +- src/parsers/PIXCfgParser.cpp | 53 +- src/parsers/PIXCfgParser.hpp | 2 - src/parsers/pix.g | 18 +- .../PIXImporterTest/test_data/pix6.fwb | 706 +++++++++--------- .../PIXImporterTest/test_data/pix7-nat.fwb | 234 +++--- 10 files changed, 573 insertions(+), 556 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 25c1b5b9c..866c5591d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,9 @@ 2011-04-07 vadim + * PIXImporterNat.cpp (buildDNATRule): resolved several problems + with import of "static" commands that use access list that matches + source or destination tcp/udp ports. See #2326, #2327 + * pix.g (network_top_level_command): see #2295 fixes in the grammar to support import of FWSM configs diff --git a/src/import/PIXImporter.cpp b/src/import/PIXImporter.cpp index 1cd1909fc..b97d49d08 100644 --- a/src/import/PIXImporter.cpp +++ b/src/import/PIXImporter.cpp @@ -46,12 +46,9 @@ #include "fwbuilder/Policy.h" #include "fwbuilder/RuleElement.h" #include "fwbuilder/Library.h" -#include "fwbuilder/ObjectMirror.h" #include "fwbuilder/TCPUDPService.h" #include "../libgui/platforms.h" -// TODO: FWBTree needs to be refactored into an independent module -#include "../libgui/FWBTree.h" #include #include @@ -347,9 +344,9 @@ FWObject* PIXImporter::mirrorServiceObjectRecursively(FWObject *obj) if (Service::cast(obj) != NULL) { - FWObject *new_obj = getMirroredServiceObject(obj); - - named_objects_registry[QString::fromUtf8(new_name.c_str())] = new_obj; + FWObject *new_obj = service_maker->getMirroredServiceObject(obj); + if (new_obj) + named_objects_registry[QString::fromUtf8(new_name.c_str())] = new_obj; res = new_obj; } else { @@ -378,37 +375,6 @@ FWObject* PIXImporter::mirrorServiceObjectRecursively(FWObject *obj) return res; } -FWObject* PIXImporter::getMirroredServiceObject(FWObject *obj) -{ - string new_name = obj->getName() + "-mirror"; - QString qs_new_name = QString::fromUtf8(new_name.c_str()); - if (named_objects_registry.count(qs_new_name) > 0) - return named_objects_registry[qs_new_name]; - - Service *new_obj = NULL; - if (TCPService::isA(obj) || UDPService::isA(obj)) - { - ObjectMirror mirror; - new_obj = mirror.getMirroredService(Service::cast(obj)); - if (new_obj!=NULL) - { - new_obj->setName(new_name); - - // obj may belong to the standard objects library if it was - // deduplicated before - FWObject *parent = obj->getParent(); - if (parent->isReadOnly()) - { - FWBTree tree ; - FWObject *slot = tree.getStandardSlotForObject( - library, new_obj->getTypeName().c_str()); - slot->add(new_obj); - } else parent->add(new_obj); - } - } - return new_obj; -} - void PIXImporter::setInterfaceAndDirectionForRuleSet( const string &ruleset_name, const string &interface_label, const string &dir) { diff --git a/src/import/PIXImporterNat.cpp b/src/import/PIXImporterNat.cpp index 0b69d7669..28502130e 100644 --- a/src/import/PIXImporterNat.cpp +++ b/src/import/PIXImporterNat.cpp @@ -216,13 +216,19 @@ void PIXImporter::buildDNATRule() RuleElement* osrc = nat_rule->getOSrc(); RuleElement* osrv = nat_rule->getOSrv(); RuleElement* tdst = nat_rule->getTDst(); + RuleElement* tsrv = nat_rule->getTSrv(); /* copy objects from a policy rule into * rule elements of a nat rule * * Src --> TDst * Dst --> OSrc - * Srv --> OSrv + * + * If Srv matches destination ports, it should be mirrored and + * placed in OSrv + * + * If it matches source ports, it goes to TSrv, mirrored + * */ RuleElement *re = policy_rule->getSrc(); FWObject::iterator it; @@ -235,7 +241,19 @@ void PIXImporter::buildDNATRule() re = policy_rule->getSrv(); for (it=re->begin(); it!=re->end(); ++it) - osrv->addRef(FWReference::getObject(*it)); + { + FWObject *old_obj = FWReference::getObject(*it); + TCPUDPService *tcpudp = TCPUDPService::cast( + mirrorServiceObjectRecursively(old_obj)); + if (tcpudp == NULL) tsrv->addRef(old_obj); + else + { + if (tcpudp->getSrcRangeEnd() > 0) + osrv->addRef(tcpudp); + if (tcpudp->getDstRangeEnd() > 0) + tsrv->addRef(tcpudp); + } + } current_ruleset->ruleset->add(nat_rule); addStandardImportComment( diff --git a/src/import/serviceObjectMaker.cpp b/src/import/serviceObjectMaker.cpp index 5b474fbc1..cf778131a 100644 --- a/src/import/serviceObjectMaker.cpp +++ b/src/import/serviceObjectMaker.cpp @@ -28,10 +28,15 @@ #include "fwbuilder/FWObjectDatabase.h" #include "fwbuilder/ICMPService.h" #include "fwbuilder/IPService.h" +#include "fwbuilder/Library.h" +#include "fwbuilder/ObjectMirror.h" #include "fwbuilder/TCPService.h" #include "fwbuilder/TagService.h" #include "fwbuilder/UDPService.h" +// TODO: FWBTree needs to be refactored into an independent module +#include "../libgui/FWBTree.h" + #include "QStringListOperators.h" #include @@ -257,3 +262,45 @@ FWObject* ServiceObjectMaker::getTagService(const QString &tagcode) return s; } +FWObject* ServiceObjectMaker::getMirroredServiceObject(FWObject *obj) +{ + string new_name = obj->getName() + "-mirror"; + QString qs_new_name = QString::fromUtf8(new_name.c_str()); + FWObject *new_obj = NULL; + if (TCPService::isA(obj) || UDPService::isA(obj)) + { + ObjectMirror mirror; + new_obj = mirror.getMirroredService(Service::cast(obj)); + if (new_obj!=NULL) + { + if (TCPService::isA(new_obj)) + TCPService::cast(new_obj)->setEstablished(false); + + ObjectSignature sig(error_tracker); + new_obj->dispatch(&sig, (void*)(NULL)); + sig.object_name = ""; + + FWObject *matching_obj = findMatchingObject(sig); + if (matching_obj) + { + delete new_obj; + return matching_obj; + } + + new_obj->setName(new_name); + + // obj may belong to the standard objects library if it was + // deduplicated before + FWObject *parent = obj->getParent(); + if (parent->isReadOnly()) + { + FWBTree tree ; + FWObject *slot = tree.getStandardSlotForObject( + library, new_obj->getTypeName().c_str()); + slot->add(new_obj); + } else parent->add(new_obj); + } + } + return new_obj; +} + diff --git a/src/import/serviceObjectMaker.h b/src/import/serviceObjectMaker.h index d23afba4a..de07a0286 100644 --- a/src/import/serviceObjectMaker.h +++ b/src/import/serviceObjectMaker.h @@ -43,6 +43,8 @@ public: virtual libfwbuilder::FWObject* createObject(ObjectSignature &sig); + libfwbuilder::FWObject* getMirroredServiceObject(libfwbuilder::FWObject *obj); + protected: virtual libfwbuilder::FWObject* getCustomService(const QString &platform, const QString &code, @@ -60,7 +62,6 @@ protected: virtual libfwbuilder::FWObject* getTagService(const QString &tagcode); - }; #endif diff --git a/src/parsers/PIXCfgParser.cpp b/src/parsers/PIXCfgParser.cpp index f9421cdea..1b9e42db1 100644 --- a/src/parsers/PIXCfgParser.cpp +++ b/src/parsers/PIXCfgParser.cpp @@ -7116,15 +7116,6 @@ void PIXCfgParser::static_starts_with_tcp_udp() { #line 7117 "PIXCfgParser.cpp" } static_real_addr_match(); - tcp_udp_port_spec(); - if ( inputState->guessing==0 ) { -#line 2196 "pix.g" - - importer->real_port_spec = importer->tmp_port_spec_2; - *dbg << "real port " << importer->real_port_spec << " "; - -#line 7127 "PIXCfgParser.cpp" - } { // ( ... )* for (;;) { if ((_tokenSet_40.member(LA(1)))) { @@ -7165,7 +7156,7 @@ void PIXCfgParser::static_mapped_addr_match() { importer->mapped_nm = importer->tmp_nm; *dbg << "mapped: " << importer->mapped_a; -#line 7169 "PIXCfgParser.cpp" +#line 7160 "PIXCfgParser.cpp" } break; } @@ -7179,7 +7170,7 @@ void PIXCfgParser::static_mapped_addr_match() { importer->mapped_nm = ""; *dbg << "mapped: " << importer->mapped_a; -#line 7183 "PIXCfgParser.cpp" +#line 7174 "PIXCfgParser.cpp" } break; } @@ -7218,7 +7209,7 @@ void PIXCfgParser::static_real_addr_match() { importer->real_nm = importer->tmp_nm; *dbg << "real: " << importer->real_a; -#line 7222 "PIXCfgParser.cpp" +#line 7213 "PIXCfgParser.cpp" } break; } @@ -7233,7 +7224,7 @@ void PIXCfgParser::static_real_addr_match() { importer->real_addr_acl = acl_name->getText(); *dbg << "real: " << importer->real_addr_acl; -#line 7237 "PIXCfgParser.cpp" +#line 7228 "PIXCfgParser.cpp" } break; } @@ -7271,7 +7262,7 @@ void PIXCfgParser::static_command_common_last_parameters() { importer->addMessageToLog( QString("Warning: 'static' command option 'dns' is not supported")); -#line 7275 "PIXCfgParser.cpp" +#line 7266 "PIXCfgParser.cpp" } break; } @@ -7284,7 +7275,7 @@ void PIXCfgParser::static_command_common_last_parameters() { importer->addMessageToLog( QString("Warning: 'static' command option 'norandomseq' is not supported")); -#line 7288 "PIXCfgParser.cpp" +#line 7279 "PIXCfgParser.cpp" } break; } @@ -7299,7 +7290,7 @@ void PIXCfgParser::static_command_common_last_parameters() { importer->real_nm = nm->getText(); *dbg << "real netmask: " << importer->real_nm; -#line 7303 "PIXCfgParser.cpp" +#line 7294 "PIXCfgParser.cpp" } break; } @@ -7332,11 +7323,11 @@ void PIXCfgParser::static_command_common_last_parameters() { max_conn = LT(1); match(INT_CONST); { - if ((LA(1) == INT_CONST) && (_tokenSet_43.member(LA(2)))) { + if ((LA(1) == INT_CONST) && (_tokenSet_42.member(LA(2)))) { max_emb_conn = LT(1); match(INT_CONST); } - else if ((_tokenSet_43.member(LA(1))) && (_tokenSet_44.member(LA(2)))) { + else if ((_tokenSet_42.member(LA(1))) && (_tokenSet_43.member(LA(2)))) { } else { throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(LT(1), getFilename()); @@ -7350,7 +7341,7 @@ void PIXCfgParser::static_command_common_last_parameters() { if (max_emb_conn) importer->static_max_emb_conn = max_emb_conn->getText(); -#line 7354 "PIXCfgParser.cpp" +#line 7345 "PIXCfgParser.cpp" } break; } @@ -7363,7 +7354,7 @@ void PIXCfgParser::static_command_common_last_parameters() { catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) { if( inputState->guessing == 0 ) { reportError(ex); - recover(ex,_tokenSet_43); + recover(ex,_tokenSet_42); } else { throw; } @@ -7731,12 +7722,12 @@ const unsigned long PIXCfgParser::_tokenSet_31_data_[] = { 671113232UL, 8369UL, // "hostname" "eq" "gt" "lt" "neq" "echo" "rip" "established" "log" "log-input" // "fragments" "time-range" "outside" const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_31(_tokenSet_31_data_,8); -const unsigned long PIXCfgParser::_tokenSet_32_data_[] = { 2818629648UL, 16791217UL, 1040704UL, 6292416UL, 0UL, 10UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; +const unsigned long PIXCfgParser::_tokenSet_32_data_[] = { 2818629648UL, 12465UL, 1040704UL, 6292416UL, 0UL, 0UL, 0UL, 0UL }; // NEWLINE IPV4 WORD IPV6 "pptp" "object" "host" "range" "ssh" "telnet" -// INT_CONST "tcp" "udp" "destination" "object-group" "dns" "hostname" -// "access-list" "eq" "gt" "lt" "neq" "echo" "rip" "established" "interface" -// "any" "log" "log-input" "fragments" "time-range" "netmask" "norandomseq" -const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_32(_tokenSet_32_data_,12); +// INT_CONST "destination" "object-group" "hostname" "access-list" "eq" +// "gt" "lt" "neq" "echo" "rip" "established" "interface" "any" "log" "log-input" +// "fragments" "time-range" +const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_32(_tokenSet_32_data_,8); const unsigned long PIXCfgParser::_tokenSet_33_data_[] = { 2684387186UL, 2172657917UL, 4294697295UL, 132121599UL, 3993042946UL, 4UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; // EOF NEWLINE "quit" "ip" "timeout" "pim" "network" "names" "name" IPV4 // WORD "object" "host" "range" "service" "http" "ssh" "telnet" "icmp" @@ -7784,20 +7775,16 @@ const unsigned long PIXCfgParser::_tokenSet_41_data_[] = { 134275072UL, 176UL, 3 // IPV4 WORD IPV6 "pptp" "ssh" "telnet" INT_CONST "hostname" "access-list" // "echo" "rip" const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_41(_tokenSet_41_data_,8); -const unsigned long PIXCfgParser::_tokenSet_42_data_[] = { 134234128UL, 16778928UL, 393280UL, 0UL, 0UL, 10UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; -// NEWLINE WORD "pptp" "ssh" "telnet" INT_CONST "tcp" "udp" "dns" "hostname" -// "echo" "rip" "netmask" "norandomseq" -const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_42(_tokenSet_42_data_,12); -const unsigned long PIXCfgParser::_tokenSet_43_data_[] = { 16UL, 16778880UL, 0UL, 0UL, 0UL, 10UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; +const unsigned long PIXCfgParser::_tokenSet_42_data_[] = { 16UL, 16778880UL, 0UL, 0UL, 0UL, 10UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; // NEWLINE INT_CONST "tcp" "udp" "dns" "netmask" "norandomseq" -const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_43(_tokenSet_43_data_,12); -const unsigned long PIXCfgParser::_tokenSet_44_data_[] = { 536903538UL, 2172659452UL, 335UL, 109051968UL, 2382364674UL, 14UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; +const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_42(_tokenSet_42_data_,12); +const unsigned long PIXCfgParser::_tokenSet_43_data_[] = { 536903538UL, 2172659452UL, 335UL, 109051968UL, 2382364674UL, 14UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL }; // EOF NEWLINE "quit" "ip" "timeout" "pim" "network" "names" "name" IPV4 // WORD "object" "service" "http" "ssh" "telnet" "icmp" INT_CONST "tcp" // "udp" "object-group" "crypto" "dns" "no" "certificate" "PIX" "ASA" "FWSM" // "hostname" "access-list" "interface" "controller" LINE_COMMENT "exit" // "nameif" "access-group" COLON_COMMENT "nat" "global" "netmask" "static" // "norandomseq" -const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_44(_tokenSet_44_data_,12); +const ANTLR_USE_NAMESPACE(antlr)BitSet PIXCfgParser::_tokenSet_43(_tokenSet_43_data_,12); diff --git a/src/parsers/PIXCfgParser.hpp b/src/parsers/PIXCfgParser.hpp index 03e8df10e..03a63ec06 100644 --- a/src/parsers/PIXCfgParser.hpp +++ b/src/parsers/PIXCfgParser.hpp @@ -319,8 +319,6 @@ private: static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_42; static const unsigned long _tokenSet_43_data_[]; static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_43; - static const unsigned long _tokenSet_44_data_[]; - static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_44; }; #endif /*INC_PIXCfgParser_hpp_*/ diff --git a/src/parsers/pix.g b/src/parsers/pix.g index aa61e5832..c1662a9d9 100644 --- a/src/parsers/pix.g +++ b/src/parsers/pix.g @@ -2188,15 +2188,15 @@ static_starts_with_tcp_udp : ( TCP | UDP ) static_real_addr_match - // <0-65535> Enter port number (0 - 65535) - // aol - // bgp - // chargen - tcp_udp_port_spec - { - importer->real_port_spec = importer->tmp_port_spec_2; - *dbg << "real port " << importer->real_port_spec << " "; - } + // <0-65535> The maximum number of simultaneous tcp connections the local IP + // hosts are to allow, default is 0 which means unlimited + // connections. Idle connections are closed after the time + // specified by the timeout conn command + // dns Use the created xlate to rewrite DNS address record + // netmask Configure Netmask to apply to IP addresses + // norandomseq Disable TCP sequence number randomization + // tcp Configure TCP specific parameters + // udp Configure UDP specific parameters ( static_command_common_last_parameters )* ; diff --git a/src/unit_tests/PIXImporterTest/test_data/pix6.fwb b/src/unit_tests/PIXImporterTest/test_data/pix6.fwb index 3bc3b66ad..26a141b1e 100644 --- a/src/unit_tests/PIXImporterTest/test_data/pix6.fwb +++ b/src/unit_tests/PIXImporterTest/test_data/pix6.fwb @@ -1,6 +1,6 @@ - + @@ -466,8 +466,8 @@ - - + + @@ -505,25 +505,32 @@ - - - - - + + + + + + + + + + + + - - - - + + + + - - - + + + - - - - + + + + @@ -534,7 +541,7 @@ - + @@ -543,23 +550,22 @@ - + - + - + - + - @@ -571,23 +577,22 @@ - + - + - + - + - @@ -596,26 +601,25 @@ - + - + - + - + - + - @@ -624,54 +628,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -680,26 +655,52 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -708,26 +709,25 @@ - + - + - + - + - + - @@ -736,13 +736,13 @@ - + - + - + @@ -751,11 +751,10 @@ - + - - + @@ -764,26 +763,25 @@ - + - + - + - + - + - - + @@ -792,31 +790,31 @@ - + - + - + - - + + - + - + @@ -825,56 +823,16 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -885,18 +843,58 @@ - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + @@ -905,18 +903,18 @@ - + - + - + @@ -925,18 +923,18 @@ - + - + - + @@ -945,18 +943,18 @@ - + - + - + @@ -965,16 +963,36 @@ - + - + + + + + + + + + + + + + + + + + + + + + @@ -985,38 +1003,18 @@ - + - - - - - - - - - - - - - - - - - - - - - + - + @@ -1025,18 +1023,18 @@ - + - + - + @@ -1045,18 +1043,18 @@ - + - + - + @@ -1065,18 +1063,18 @@ - + - + - + @@ -1085,18 +1083,18 @@ - + - + - + @@ -1105,18 +1103,18 @@ - + - + - + @@ -1125,18 +1123,18 @@ - + - + - + @@ -1145,18 +1143,18 @@ - + - + - + @@ -1165,18 +1163,18 @@ - + - + - + @@ -1185,18 +1183,18 @@ - + - + - + @@ -1205,7 +1203,7 @@ - + @@ -1216,7 +1214,7 @@ - + @@ -1225,7 +1223,7 @@ - + @@ -1233,10 +1231,10 @@ - + - + @@ -1245,7 +1243,7 @@ - + @@ -1256,7 +1254,7 @@ - + @@ -1265,7 +1263,7 @@ - + @@ -1276,7 +1274,7 @@ - + @@ -1285,7 +1283,7 @@ - + @@ -1296,7 +1294,7 @@ - + @@ -1305,7 +1303,7 @@ - + @@ -1315,87 +1313,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1403,11 +1320,30 @@ - - + - + + + + + + + + + + + + + + + + + + + + + @@ -1424,22 +1360,84 @@ - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1448,18 +1446,18 @@ - + - + - + @@ -1468,7 +1466,7 @@ - + @@ -1479,7 +1477,7 @@ - + @@ -1488,18 +1486,18 @@ - + - + - + @@ -1508,18 +1506,18 @@ - + - + - + @@ -1528,18 +1526,18 @@ - + - + - + @@ -1548,18 +1546,18 @@ - + - + - + @@ -1568,18 +1566,18 @@ - + - + - + @@ -1588,7 +1586,7 @@ - + @@ -1599,7 +1597,7 @@ - + @@ -1608,7 +1606,7 @@ - + @@ -1619,7 +1617,7 @@ - + @@ -1631,8 +1629,8 @@ - - + + @@ -1654,8 +1652,8 @@ - - + + @@ -1677,14 +1675,14 @@ - + - + - - + + @@ -1705,7 +1703,7 @@ - - + + diff --git a/src/unit_tests/PIXImporterTest/test_data/pix7-nat.fwb b/src/unit_tests/PIXImporterTest/test_data/pix7-nat.fwb index afe6999ea..e8d45f8cc 100644 --- a/src/unit_tests/PIXImporterTest/test_data/pix7-nat.fwb +++ b/src/unit_tests/PIXImporterTest/test_data/pix7-nat.fwb @@ -1,6 +1,6 @@ - + @@ -506,8 +506,8 @@ - - + + @@ -531,7 +531,7 @@ - + @@ -540,10 +540,10 @@ - + - + @@ -567,10 +567,10 @@ - + - + @@ -594,10 +594,10 @@ - + - + @@ -621,10 +621,10 @@ - + - + @@ -648,10 +648,10 @@ - + - + @@ -675,10 +675,10 @@ - + - + @@ -702,10 +702,10 @@ - + - + @@ -729,10 +729,10 @@ - + - + @@ -756,10 +756,10 @@ - + - + @@ -774,7 +774,7 @@ - + @@ -783,10 +783,10 @@ - + - + @@ -801,7 +801,7 @@ - + @@ -810,10 +810,10 @@ - + - + @@ -828,7 +828,7 @@ - + @@ -837,10 +837,10 @@ - + - + @@ -864,10 +864,10 @@ - + - + @@ -891,10 +891,10 @@ - + - + @@ -918,10 +918,10 @@ - + - + @@ -945,10 +945,10 @@ - + - + @@ -972,10 +972,10 @@ - + - + @@ -999,10 +999,10 @@ - + - + @@ -1011,7 +1011,7 @@ - + @@ -1026,10 +1026,10 @@ - + - + @@ -1050,13 +1050,13 @@ - + - + - + @@ -1077,13 +1077,13 @@ - + - + - + @@ -1092,11 +1092,10 @@ - + - @@ -1105,26 +1104,25 @@ - + - + - + - + - + - @@ -1133,44 +1131,44 @@ - + - + - + - + - + - - - - - - - - - + + + + + + + + + - + - + - + @@ -1178,7 +1176,7 @@ - + @@ -1187,17 +1185,17 @@ - + - + - + - + @@ -1205,7 +1203,7 @@ - + @@ -1214,17 +1212,17 @@ - + - + - + - + @@ -1232,7 +1230,7 @@ - + @@ -1241,13 +1239,13 @@ - + - + - + @@ -1265,7 +1263,7 @@ - + @@ -1285,7 +1283,7 @@ - + @@ -1305,7 +1303,7 @@ - + @@ -1325,7 +1323,7 @@ - + @@ -1346,7 +1344,7 @@ - + @@ -1367,7 +1365,7 @@ - + @@ -1388,7 +1386,7 @@ - + @@ -1408,7 +1406,7 @@ - + @@ -1429,7 +1427,7 @@ - + @@ -1450,7 +1448,7 @@ - + @@ -1471,7 +1469,7 @@ - + @@ -1492,7 +1490,7 @@ - + @@ -1512,7 +1510,7 @@ - + @@ -1533,7 +1531,7 @@ - + @@ -1554,7 +1552,7 @@ - + @@ -1575,7 +1573,7 @@ - + @@ -1596,7 +1594,7 @@ - + @@ -1608,28 +1606,28 @@ - + - + - - + + - - + + - - + + @@ -1650,7 +1648,7 @@ - - + +