diff --git a/.gitignore b/.gitignore index fbb3d27..e3270a5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ NOTES* .DS_Store vendor/db_generator vendor/db_generator-* +vendor/parameter_files +vendor/parameter_files-* diff --git a/Gemfile b/Gemfile index 22b3d23..d360bdd 100644 --- a/Gemfile +++ b/Gemfile @@ -9,3 +9,4 @@ end gem "docopt" gem "ruby-ip" gem "open4" +gem "ipaddress" diff --git a/Gemfile.lock b/Gemfile.lock index 50da9c7..5df3e23 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,6 +2,7 @@ GEM remote: http://rubygems.org/ specs: docopt (0.5.0) + ipaddress (0.8.3) open4 (1.3.4) ruby-ip (0.9.3) @@ -11,8 +12,9 @@ PLATFORMS DEPENDENCIES bundler docopt + ipaddress open4 ruby-ip BUNDLED WITH - 1.10.6 + 1.15.4 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile index e9f0190..02f37af 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,6 @@ # (downloads, patches and compiles ClassBench) all: make -C vendor all + +clean: + $(MAKE) -C vendor $@ diff --git a/README.md b/README.md index ee8bda4..e1f179d 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,114 @@ -# Classbench - -Utility for generation of firewall/OpenFlow rules based on original (no longer maintained) [Classbench](http://www.arl.wustl.edu/classbench/). +# ClassBench-ng +A tool for generation of synthetic classification rule sets for benchmarking, which is based on original (no longer maintained) [ClassBench](http://www.arl.wustl.edu/classbench/). +The format of the generated rules can be one of the following: +- IPv4 5-tuple +- IPv6 5-tuple +- OpenFlow ## Requirements +- Python3 - Ruby 1.9.3+ - RubyGems - ``` sudo gem install open4 ruby-ip docopt ipaddress ``` + ## Installation ``` -git clone https://github.com/lucansky/classbench-ng.git -make # Downloads, patches and compiles db_generator in ./vendor/db_generator/db_generator +git clone https://github.com/classbench-ng/classbench-ng.git +make # Downloads, patches and compiles original ClassBench in ./vendor/db_generator + # Downloads the parameter files of original ClassBench to ./vendor/parameter_files ``` -### Patching classbench -Due to statically initialized arrays in ClassBench, patching is required which increases the limit. -Patch is automatically applied by make in process of downloading ClassBench. -(see vendor/Makefile) +### Patching ClassBench +Original ClassBench is patched using `./patches/improvements_ipv6.patch` and the size of its statically initialized arrays is increased, where necessary. +These changes are automatically applied on downloaded original ClassBench during ClassBench-ng installation. + +By modifying `./vendor/Makefile` the user can select a different patch from `./patches` directory to be applied during installation. +Basic characteristics of patches available in `./patches` directory and suggestions when to use them are following: + +`improvements.patch` +- improves precision of IPv4 prefixes generation +- use when IPv6 prefixes generation is not required + +`ipv6.patch` +- adds support for IPv6 prefixes generation +- use when IPv6 prefixes generation is required and precision of IPv4/IPv6 prefixes generation is not crucial + +`improvements_ipv6.patch` +- adds support for IPv6 prefixes generation and improves precision of both IPv4 and IPv6 prefixes generation +- use when IPv6 prefixes generation is required and precision of IPv4/IPv6 prefixes generation is crucial ## Usage +ClassBench-ng can be used in two different ways: +- To analyse an existing rule set and extract a corresponding SEED. +- To generate a synthetic rule set from an input SEED. + ``` -./classbench analyse FILE +./classbench -h | --help ``` -Analyses file, expecting FILE to be ovs-ofctl dump. -Fields extracted from dump are: -- dl_dst, dl_src, dl_type, dl_vlan, dl_vlan_pcp, -- eth_type, in_port, -- nw_dst, nw_proto, nw_src, nw_tos, -- tp_dst, tp_src +Prints detailed usage information. -Output's original Classbench seed with openflow YAML structure as last section. +### ClassBench-ng Analyser +The current version can successfully analyse IPv4 5-tuples, IPv6 5-tuples, and OpenFlow rules. ``` -./classbench generate v4 SEED [--count=100] [--db-generator=] +./classbench analyse tuples FILE FORMAT [-l] +``` +Analyses FILE, expecting FILE to be in the format specified in FORMAT (see `./lib/tuples_analyzer/README` for more information on how to specify the format). +- `-l` enables printing analysis error logs. + +The output is an original ClassBench seed. + ``` -Generates --count of OpenFlow rules. -If seed without OpenFlow section is provided, regular 5-tuples are generated. -Output format is "attribute=value", joined by ", ". +./classbench analyse of FILE +``` +Analyses FILE, expecting FILE to be in the format used by `ovs-ofctl`. +Fields extracted from FILE are: +- in_port, +- dl_src, dl_dst, eth_type, dl_vlan, dl_vlan_pcp, +- nw_src, nw_dst, nw_tos, nw_proto, +- tp_src, tp_dst + +The output is an original ClassBench seed with an OpenFlow YAML structure as the last section. + +### ClassBench-ng Rule Generator +The current version can successfully generate IPv4, IPv6 and OpenFlow 1.0 flow rules. +- IPv4 SEEDs can be found in `./vendor/parameter_files` +- OpenFlow SEEDs can be found in `./seeds` + +``` +./classbench generate v4 SEED [--count=] [--db-generator=] +``` +Generates IPv4 5-tuples following the properties from SEED. +- `--count=` specifies the number of 5-tuples to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) + +The output format is the same as of original ClassBench outputs. + +``` +./classbench generate v6 SEED [--count=] [--db-generator=] +``` +Generates IPv6 5-tuples following the properties from SEED. +- `--count=` specifies the number of 5-tuples to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) + +The output format is the same as of original ClassBench outputs. + +``` +./classbench generate of SEED [--count=] [--db-generator=] +``` +Generates OpenFlow rules following the properties from SEED that has to contain an OpenFlow section. +- `--count=` specifies the number of rules to be generated (default: `100`) +- `--db-generator=` specifies the path to an original ClassBench binary (default: `./vendor/db_generator/db_generator`) + +The output consists of `attribute=value` pairs joined by `, `. + +## Known Issues +- the number of generated rules is usually lower than in original ClassBench (i.e., ClassBench-ng generates higher number of redundant rules that are removed in the last phase) +- ClassBench-ng Analyser does not correctly analyses source/destination port prefixes specified using a bit map in the ovs-ofctl format +## How to Contribute +Contributions are welcome via: +- pull requests (preferred) +- e-mail to imatousek at fit.vutbr.cz diff --git a/classbench b/classbench index 7d88359..e030cd3 100755 --- a/classbench +++ b/classbench @@ -5,47 +5,62 @@ require_relative "lib/classbench" require "pp" require "docopt" doc = < [--count=] [--db-generator=] - #{__FILE__} generate v6 [--count=] + #{__FILE__} analyse tuples FILE FORMAT [-l] + #{__FILE__} analyse of FILE + #{__FILE__} generate v4 SEED [--count=] [--db-generator=] + #{__FILE__} generate v6 SEED [--count=] [--db-generator=] + #{__FILE__} generate of SEED [--count=] [--db-generator=] #{__FILE__} -h | --help - #{__FILE__} version Options: - --db-generator= Path to binary of original db_generator [default: ./vendor/db_generator/db_generator] - --count= Count of rules to generate [default: 100] + -l Enable printing analysis error logs. + --db-generator= Path to an original ClassBench binary. + [default: ./vendor/db_generator/db_generator] + --count= The number of rules to be generated. + [default: 100] -h --help Show this screen. -Analyser accept's as input ovs-ofctl dump. -Fields extracted from dump are: - - dl_dst, dl_src, dl_type, (dl_vlan, dl_vlan_pcp,) - - eth_type, in_port, - - nw_dst, nw_proto, nw_src, nw_tos, - - tp_dst, tp_src -Output is original Classbench seed - with openflow YAML structure as last section. +Analyser accepts as an input either a rule set in a given format in case of +"analyse tuples" (the expected structure of a format file is described in +lib/tuples_analyzer/README, section 7) or an ovs-ofctl dump in case of +"analyse of". +The output is an original ClassBench seed or this seed with an OpenFlow YAML +structure as the last section, respectively. -Generator accept's Classbench seed with openflow section. -Output's one rule per line in format "attribute=value", joined by ", ". +Generator accepts as an input an original ClassBench seed that has to contain +an OpenFlow section in case of "generate of". +The output is either the same as of original ClassBench outputs or it consists +of "attribute=value" pairs joined by ", ". DOCOPT +# Add the following line to the DOCOPT's "Options" pattern to show support of +# "version" parameter. +# #{__FILE__} version begin opts = Docopt::docopt(doc) if opts["analyse"] - Classbench::analyse(opts["FILE"]) + if opts["tuples"] + Classbench::analyse_tuples(opts["FILE"], opts["FORMAT"], opts["-l"]) + elsif opts["of"] + Classbench::analyse_of(opts["FILE"]) + end elsif opts["generate"] - #pp opts - Classbench::generate(opts[""], (opts["--count"].to_i), opts["--db-generator"]) + if opts["v4"] + Classbench::generate("v4", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) + elsif opts["v6"] + Classbench::generate("v6", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) + elsif opts["of"] + Classbench::generate("of", opts["SEED"], (opts["--count"].to_i), opts["--db-generator"]) + end elsif opts["version"] puts "Version: #{Classbench::VERSION}" - end - # TODO: --version + end -rescue Docopt::Exit => e - STDERR.puts e.message + rescue Docopt::Exit => e + STDERR.puts e.message end diff --git a/lib/classbench.rb b/lib/classbench.rb index b594031..756cd46 100644 --- a/lib/classbench.rb +++ b/lib/classbench.rb @@ -32,23 +32,49 @@ def self.load_prefixes_from_file(filename) t end - def self.analyse(filename) + def self.analyse_tuples(rules_filename, format_filename, logs_enabled) + if logs_enabled + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename, "-l") + else + pid, stdin, stdout, stderr = Open4::popen4("python3", "-m", "lib.tuples_analyzer", "-r", rules_filename, "-f", format_filename) + end + + ignored, status = Process::waitpid2 pid + + if status.exitstatus == 0 + STDOUT.puts stdout.read.strip + if logs_enabled + warnings = stderr.read.strip + if !warnings.to_s.empty? + STDERR.puts warnings + end + end + else + STDERR.puts stderr.read.strip + exit(status.exitstatus) + end + + end + + def self.analyse_of(filename) analyser = Analyser.new analyser.parse_openflow(File.read(filename)) - analyser.calculate_stats - puts analyser.generate_seed end - def self.generate(filename, count, db_generator_path) + def self.generate(format, filename, count, db_generator_path) generator = Generator.new(filename, db_generator_path) - has_openflow = generator.parse_seed + if format == "of" + if !generator.parse_seed + return + end + end #puts YAML.dump(generator.openflow_section) - rules = generator.generate_rules(count) - if has_openflow + rules = generator.generate_rules(format, count) + if format == "of" rules.map!(&:to_vswitch_format) end diff --git a/lib/classbench/analyser.rb b/lib/classbench/analyser.rb index 8b2ffcf..df1a01b 100644 --- a/lib/classbench/analyser.rb +++ b/lib/classbench/analyser.rb @@ -34,6 +34,8 @@ def parse_openflow(lines) end self.rules << Rule.new(rule) end + + calculate_stats end def rules_per_port_class(class_name) @@ -41,8 +43,6 @@ def rules_per_port_class(class_name) end def generate_seed - calculate_stats - seed = "" seed += "-scale\n#{rules.size}\n#\n" @@ -188,7 +188,7 @@ def calculate_stats lengths_of_class = port_class_prefix_lengths[r.port_class_name] specific_length = lengths_of_class[r.src_length + r.dst_length] ||= {} - specific_length[r.dst_length] = (specific_length[r.dst_length] || 0) + 1 + specific_length[r.src_length] = (specific_length[r.src_length] || 0) + 1 end end diff --git a/lib/classbench/generator.rb b/lib/classbench/generator.rb index 42ac08c..4c7aa40 100644 --- a/lib/classbench/generator.rb +++ b/lib/classbench/generator.rb @@ -57,7 +57,7 @@ def parse_seed #p self.openflow_section rescue NoMethodError - STDERR.puts "No openflow section found in seed." + STDERR.puts "No openflow section found in the seed." return false end @@ -113,15 +113,23 @@ def pregenerate_eth_types end ########################## - def generate_classbench_rules(count) + def generate_classbench_rules(format, count) current_dir = File.dirname(__FILE__) tmp_filters = Tempfile.new('filters') - # db_generator -c filename #{count} 0 0 0 tmp/#{rand} - # Call classbench - #system(current_dir+"/db_generator", "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") - pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) - ignored, status = Process::waitpid2 pid + if format == "v6" + # db_generator -c6 filename #{count} 0 0 0 tmp/#{rand} + # Call classbench + #system(current_dir+"/db_generator", "-c6", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") + pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c6", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) + ignored, status = Process::waitpid2 pid + else # format == "v4" || format format == "of" + # db_generator -c filename #{count} 0 0 0 tmp/#{rand} + # Call classbench + #system(current_dir+"/db_generator", "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path, " > /dev/null") + pid, stdin, stdout, stderr = Open4::popen4(self.db_generator_path, "-c", self.seed_path, count.to_s, "0", "0", "0", tmp_filters.path) + ignored, status = Process::waitpid2 pid + end #STDERR.puts "done" #puts status @@ -135,15 +143,24 @@ def generate_classbench_rules(count) return raw_rules end - def generate_rules(count) - generate_classbench_rules(count) + def generate_rules(format, count) + generate_classbench_rules(format, count) - if not self.openflow_section + if format != "of" return self.raw_rules end return classbench_rules.map do |rule| - random_openflow_type = pregenerated_rule_types.sample + + begin + random_openflow_type = pregenerated_rule_types.sample + end while ((random_openflow_type.include?("nw_proto") and rule.attributes["nw_proto"] == 0) or + ((not random_openflow_type.include?("nw_proto")) and (not rule.attributes["nw_proto"] == 0)) or + (random_openflow_type.include?("tp_src") and rule.attributes["tp_src"] == (0..65535)) or + ((not random_openflow_type.include?("tp_src")) and (not rule.attributes["tp_src"] == (0..65535))) or + (random_openflow_type.include?("tp_dst") and rule.attributes["tp_dst"] == (0..65535)) or + ((not random_openflow_type.include?("tp_dst")) and (not rule.attributes["tp_dst"] == (0..65535)))) + rule.remove_missing_attributes(random_openflow_type) #p random_openflow_type @@ -159,15 +176,16 @@ def generate_rules(count) rule.attributes["eth_type"] = pregenerated_eth_types.sample end - random_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") + random_dst_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") if attribute == "dl_dst" random_vendor = pregenerated_dl_dsts.sample - rule.attributes["dl_dst"] = random_vendor + ":" + random_device_mac + rule.attributes["dl_dst"] = random_vendor + ":" + random_dst_device_mac end + random_src_device_mac = (1..3).collect { "%02x" % [rand(255)] }.join(":") if attribute == "dl_src" random_vendor = pregenerated_dl_srcs.sample - rule.attributes["dl_src"] = random_vendor + ":" + random_device_mac + rule.attributes["dl_src"] = random_vendor + ":" + random_src_device_mac end if attribute == "dl_vlan" diff --git a/lib/classbench/rule.rb b/lib/classbench/rule.rb index 47ce8d5..41aa04c 100644 --- a/lib/classbench/rule.rb +++ b/lib/classbench/rule.rb @@ -32,11 +32,11 @@ def self.from_classbench_format(line) end def src_length - IPAddress.parse(attributes["nw_src"] || '0.0.0.0').prefix.to_i + IPAddress.parse(attributes["nw_src"] || '0.0.0.0/0').prefix.to_i end def dst_length - IPAddress.parse(attributes["nw_dst"] || '0.0.0.0').prefix.to_i + IPAddress.parse(attributes["nw_dst"] || '0.0.0.0/0').prefix.to_i end def remove_missing_attributes(attrs) @@ -101,6 +101,7 @@ def l2_vendor(type) def to_vswitch_format attributes.to_a. + reject {|k,v| k == "nw_proto" and v == 0}. # nw_proto is removed when wildcard reject {|k,v| v == (0..65535)}. # tp_src and tp_dst is removed when wildcard map {|k,v| (v.is_a?(Range) and v.first == v.last) ? [k, v.first] : [k,v] }. # if port range is [x..x] => x map {|k,v| "#{k}=#{v}" }.join(", ") # Openflow format diff --git a/lib/tuples_analyzer/README b/lib/tuples_analyzer/README new file mode 100644 index 0000000..8ab9143 --- /dev/null +++ b/lib/tuples_analyzer/README @@ -0,0 +1,111 @@ +1.PROGRAM: + tuples_analyzer + +2.FUNCTION: + Program creates parameter file from statistics and distributions of real filter set. + File with format of rules is needed for processing filter rules. Format is described in section 7. + Computed parameters are then used to generate synthetic filter set by tools ClassBench and ClassBench-ng. + +3.USAGE: + python3 -m tuples_analyzer -r -f [-o -l -h] + +4.USAGE EXAMPLES: + a.) python3 -m tuples_analyzer -h + b.) python3 -m tuples_analyzer -r rules.txt -f format.txt + c.) python3 -m tuples_analyzer -r rules.txt -f format.txt -l + d.) python3 -m tuples_analyzer -r rules.txt -f format.txt -o output.txt + e.) python3 -m tuples_analyzer -r rules.txt -f format.txt -o output.txt -l + +5.MANDATORY ARGUMENTS: + -r rules_file | --rules=rules_file specify path to file with filter rules + -f format_file | --format=format_file specify path to file with format of rules + +6.OPTIONAL ARGUMENTS: + -o output_file | --output=output_file specify path to file, which will be created + to store computed parameters + + -l | --logs printing error logs during computation is enabled + -h | --help display manual + +7.FORMAT OF RULES: + Format tells, how one rule in set should look like. Program loads format from first line of format file. Specify path to + file with argument '-f'. + + Format of rule is sentence consisting of parameters and keywords. Parameters (specified uppercase words) are like + variables. They always represent different value in filter rule than its notation in format. E.g. parameter 'PROTOCOL' + in format, represents network protocol abbreviation in rule (e.g. 'tcp'). Keywords in format are exactly same strings + in rule (e.g. 'from', 'to'). + + Order of placement parameters and keywords in format sentence is important. In process of parsing + rule, is from beginning of rule to its end checked, if every part of rule matches to its definition + in format. E.g. if format starts with 'from SRC_IP', it is expected, that first part of rule will be + 'from' (same as 'from' in format) and second part will be ip address for example '10.10.10.0/24' + (parameter 'SRC_IP' representation). If order is not correct, rule will be ignored. + + a.)parameters + + Parameters (PROTOCOL, SRC_IP, SRC_PORT, DST_IP, DST_PORT, NUMBER, WILDCARD) in format definition tell, what type of + value is expected on same position in rule. What every parameter represents is described in this list: + + PROTOCOL network protocol abbreviation + SRC_IP source IPv4 or IPv6 address + SRC_PORT source port or port range + DST_IP destination IPv4 or IPv6 address + DST_PORT destination port or port range + NUMBER some number, not used for computation parameters + WILDCARD some string, not used for computation parameters + + b.)supported representation of parameters in rules + + Supported IPv4 and IPv6 address definitions are with or without mask in digit form, e.g.: 2001:db8:a::/64, 192.168.0.33 + Supported port definitions are port number or port range, e.g.: 80, 0:1023 + All supported network protocol case-insensitive abbreviations are: + 'ICMP', 'IGMP', 'GGP', 'ST', 'TCP', 'EGP', 'UDP', 'GRE', 'ESP', 'AH', 'EIGRP', 'OSPFIGP' + All supported wildcard values of parameters are: 'any', 'all', '*', 'ip', '0' + + b.)keywords + + Keywords are every possible strings except all parameters and character '?'. Keywords in format definition tell, + that exactly same string value as keywords is expected on same position in rule. They does not represent valuable + content for computation parameters. They are usually used to introduce parameters. E.g. if you define your format + starting with 'from=SRC_IP', then rule definition in filter set can start with 'from=10.10.10.0/24'. + + Characters ' ', ',', '=' (empty space, comma, equal) are used as separators between parameters and keywords + in format and also separators between parts in filter rules. + + c.)optional parts + + You can define optional parts of rule in your format definition, if you after parameter or keyword + add character '?'. E.g. if format ends with 'ip-port?=DST_PORT?', then at the end of rule is not + required any of these words 'ip-port' or '0:1023' (example of port range) but they can both + be there (of course in correct order). + + +8.FORMAT OF RULES EXAMPLES: + Example sets and formats are located in examples folder. + + a.) custom1.format: + PROTOCOL from SRC_IP SRC_PORT to DST_IP DST_PORT + + b.) custom2.format: + PROTOCOL destination DST_IP ip-port? DST_PORT? source SRC_IP ip-port? SRC_PORT? + + c.)custom_with_ipv6.format: + rule NUMBER WILDCARD PROTOCOL source? SRC_IP? destination? DST_IP? destination-port DST_PORT? + + d.) openflow.format: + nw_proto=PROTOCOL, nw_src?=SRC_IP?, nw_dst?=DST_IP?, tp_src?=SRC_PORT?, tp_dst?=DST_PORT? + + e.)iptables_long.format (long format): + iptables WILDCARD WILDCARD --source? SRC_IP? --destination? DST_IP? --protocol? PROTOCOL? --source-port? SRC_PORT? --destination-port? DST_PORT? -j WILDCARD + + f.)iptables_short.format (short format): + iptables WILDCARD WILDCARD -s? SRC_IP? -d? DST_IP? -p? PROTOCOL? --sport? SRC_PORT? --dport? DST_PORT? -j WILDCARD + + g.)ipfw.format: + ipfw add WILDCARD PROTOCOL? from SRC_IP? SRC_PORT? to DST_IP? DST_PORT? + + +9.AUTHOR: + Jozef Sabo + xsaboj00@stud.fit.vutbr.cz diff --git a/lib/tuples_analyzer/__init__.py b/lib/tuples_analyzer/__init__.py new file mode 100644 index 0000000..9429a2c --- /dev/null +++ b/lib/tuples_analyzer/__init__.py @@ -0,0 +1 @@ +"""Main package of program.""" diff --git a/lib/tuples_analyzer/__main__.py b/lib/tuples_analyzer/__main__.py new file mode 100644 index 0000000..251f817 --- /dev/null +++ b/lib/tuples_analyzer/__main__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +"""Main module for launching program.""" + +from .calculation_parameters.parameter_file import ParameterFile +from .processing_arguments.processed_arguments import ProcessedArguments +from .processing_files.processing_file_helper import ProcessingFileHelper +from .processing_rules.filter_rule_generator import FilterRuleGenerator + +if __name__ == "__main__": + # instance of class ProcessedArguments contains all processed command line arguments + processed_arguments = ProcessedArguments() + + # generator of lines from filter set file + lines_generator = ProcessingFileHelper.create_lines_generator(processed_arguments.rules_path) + + # string with format of rules in filter set + rule_format = ProcessingFileHelper.get_format(processed_arguments.format_path) + + # generator of FilterRule class instances + rule_generator = FilterRuleGenerator.create_generator(lines_generator, rule_format, processed_arguments.is_stderr_on) + + # instance of class ParameterFile creates and holds all parameters + parameter_file = ParameterFile(rule_generator, processed_arguments.output_path) + + # printing calculated parameters to output + parameter_file.print_parameters() diff --git a/lib/tuples_analyzer/calculation_parameters/__init__.py b/lib/tuples_analyzer/calculation_parameters/__init__.py new file mode 100644 index 0000000..c97a818 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/__init__.py @@ -0,0 +1 @@ +"""Package with classes for computation parameters.""" diff --git a/lib/tuples_analyzer/calculation_parameters/distribution.py b/lib/tuples_analyzer/calculation_parameters/distribution.py new file mode 100644 index 0000000..56a8d30 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/distribution.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +"""Module containing definition of class Distribution.""" + +from collections import Counter + + +class Distribution: + """ + Class representing distribution over different type of values. + """ + + def __init__(self): + """ + Constructor initialize instance variable total_counts with zero. + Variable distribution is initialized as new instance of class Counter. + Counter is collection for counting objects. + """ + self.total_count = 0 + """Total count of values in distribution.""" + self.distribution = Counter() + """Variable holding count of every unique value in distribution.""" + + def add_value(self, value): + """ + When adding new value to distribution, total counts of values has to be incremented by one and + instance variable distribution has to be updated with new value (updating counts of unique values in collection + Counter). + + :param value: Distribution value. + """ + self.total_count += 1 + self.distribution.update({value: 1}) diff --git a/lib/tuples_analyzer/calculation_parameters/enums/__init__.py b/lib/tuples_analyzer/calculation_parameters/enums/__init__.py new file mode 100644 index 0000000..2997f06 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while computation parameters.""" diff --git a/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py b/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py new file mode 100644 index 0000000..c26fe79 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/port_distribution_type.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PortDistributionType.""" + +from enum import Enum + + +class PortDistributionType(Enum): + """ + Enum for every possible distribution type of port values. + """ + + SPAR = 0 + """Source arbitrary port ranges distribution.""" + SPEM = 1 + """Source exact match ports distribution.""" + DPAR = 2 + """Destination arbitrary port ranges distribution.""" + DPEM = 3 + """Destination exact match ports distribution.""" diff --git a/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py b/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py new file mode 100644 index 0000000..dfa63cc --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/enums/trie_type.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class TrieType.""" + +from enum import Enum + + +class TrieType(Enum): + """ + Enum for types of trie (binary prefix tree). + """ + + SPT = 0 + """Trie created from source prefixes of filter rules.""" + DPT = 1 + """Trie created from destination prefixes of filter rules.""" diff --git a/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py b/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py new file mode 100644 index 0000000..70a39ba --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/interfaces/IParameter.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +"""Module containing definition of interface IParameter.""" + +from abc import ABCMeta, abstractmethod + + +class IParameter: + """ + Interface which has to be implemented by all parameter computation classes. + """ + __metaclass__ = ABCMeta + + @abstractmethod + def extract_data(self, filter_rule): + """ + Function extracts all needed data from FilterRule instance to compute specific parameter. + Extracted data are stored in instance variables. + + :param filter_rule: FilterRule instance. + """ + pass + + @abstractmethod + def compute_parameter(self): + """ + Function computes parameter from all extracted data. + + :return: Computed parameter. + """ + pass + + @abstractmethod + def print_parameter(self, output): + """ + Function prints parameter to output in ClassBench format. + + :param output: OutputPrint instance. + """ + pass diff --git a/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py b/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py new file mode 100644 index 0000000..91d2233 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/interfaces/__init__.py @@ -0,0 +1 @@ +"""Package with interface implemented by all parameter classes.""" diff --git a/lib/tuples_analyzer/calculation_parameters/parameter_file.py b/lib/tuples_analyzer/calculation_parameters/parameter_file.py new file mode 100644 index 0000000..cd03da3 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/parameter_file.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +"""Module containing definition of class ParameterFile.""" + +from .enums.port_distribution_type import PortDistributionType +from .enums.trie_type import TrieType +from .port_distribution import PortDistribution +from .ppc_prefixlen_distribution import PpcPrefixLenDistribution +from .prefix_correlation_distribution import PrefixCorrelationDistribution +from .protocol_ppc_distribution import ProtocolPpcDistribution +from .trie_distributions import TrieDistributions +from ..printing_output.output_print import OutputPrint +from ..processing_rules.enums.port_pair_class import PPC + + +class ParameterFile: + """ + Class representing parameter file. + Every parameter located in ClassBench parameter file has its own class. + This class holds all instances of parameter classes required to create desired parameter file. + """ + loaded_rules = 0 + """Count of processed rules in process of extraction data.""" + + def __init__(self, rule_generator, output_path): + """ + Constructor initialize instance variables as new instances of parameter classes, rule generator class + and output class. + It also calls function load_rules() to load parameter instances with extracted data from filter rules. + + :param rule_generator: Generator of FilterRule instances. + + :param output_path: Path to file, where user wants to save computed parameters. + """ + self.rule_generator = rule_generator + """Generator of FilterRule instances.""" + self.output = OutputPrint(output_path) + """Instance of class used to print computed parameters to output.""" + self.protocol_ppc_distribution = ProtocolPpcDistribution() + """Instance of class ProtocolPpcDistribution.""" + self.port_distributions = [] + """List of instances of class PortDistribution.""" + i = 0 + while i < 4: + self.port_distributions.insert(i, PortDistribution(PortDistributionType(i))) + i += 1 + + self.ppc_prefix_length_distributions = [] + """List of instances of class PpcPrefixLenDistribution.""" + i = 0 + while i < 25: + self.ppc_prefix_length_distributions.insert(i, PpcPrefixLenDistribution(PPC(i))) + i += 1 + + self.trie_distributions = [] + """List of instances of class TrieDistributions.""" + i = 0 + while i < 2: + self.trie_distributions.insert(i, TrieDistributions(TrieType(i))) + i += 1 + + self.prefix_correlation_distribution = PrefixCorrelationDistribution() + """Instance of class PrefixCorrelationDistribution.""" + + self.load_parameters() + + def load_parameters(self): + """ + Function fills structures of all parameter instances with data needed to calculate parameters. + Data are extracted from generator of FilterRule instances. + """ + for rule in self.rule_generator: + self.protocol_ppc_distribution.extract_data(rule) + + for port_distribution in self.port_distributions: + port_distribution.extract_data(rule) + + for ppc_prefix_length_distribution in self.ppc_prefix_length_distributions: + ppc_prefix_length_distribution.extract_data(rule) + + for trie_distributions in self.trie_distributions: + trie_distributions.extract_data(rule) + + self.prefix_correlation_distribution.extract_data(rule) + ParameterFile.loaded_rules += 1 + + def print_parameters(self): + """ + Function calls print functions of all parameter instances to print calculated parameters in ClassBench format. + """ + self.output.print('-scale') + self.output.print(str(ParameterFile.loaded_rules)) + self.output.print('#') + + self.protocol_ppc_distribution.print_parameter(self.output) + + self.output.print('-flags') + self.output.print('#') + + self.output.print('-extra') + self.output.print('0') + self.output.print('#') + + for port_distribution in self.port_distributions: + port_distribution.print_parameter(self.output) + + for ppc_prefix_length_distribution in self.ppc_prefix_length_distributions: + ppc_prefix_length_distribution.print_parameter(self.output) + + for trie_distributions in self.trie_distributions: + trie_distributions.print_parameter(self.output) + + self.prefix_correlation_distribution.print_parameter(self.output) diff --git a/lib/tuples_analyzer/calculation_parameters/port_distribution.py b/lib/tuples_analyzer/calculation_parameters/port_distribution.py new file mode 100644 index 0000000..1db1f92 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/port_distribution.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +"""Module containing definition of class PortDistribution.""" + +from .distribution import Distribution +from .enums.port_distribution_type import PortDistributionType +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format +from ..processing_rules.enums.port_class import PC + + +class PortDistribution(IParameter): + """ + Class representing parameter: port values distribution. + There are 4 types of port values distributions (SPAR, SPEM, DPAR, DPEM). + Type of distribution tells from which port values of filter rules will be created distribution. + Types are more described in enum class PortDistributionClass. + """ + + def __init__(self, port_distribution_type): + """ + Parameter of constructor decides which type of port values distribution will be represented by created instance + of that class. + + :param port_distribution_type: Enum value of type of port values distribution. + """ + self.distribution_type = port_distribution_type + """Type of port values distribution.""" + self.distribution = Distribution() + """Distribution of unique port values.""" + + def extract_data(self, filter_rule): + """ + Function updates instance variable distribution with new counts of unique port values extracted from filter rules. + + :param filter_rule: FilterRule instance. + """ + if self.distribution_type == PortDistributionType.SPAR and filter_rule.src_port_class == PC.AR: + self.distribution.add_value(filter_rule.src_port) + + elif self.distribution_type == PortDistributionType.SPEM and filter_rule.src_port_class == PC.EM: + self.distribution.add_value(filter_rule.src_port) + + elif self.distribution_type == PortDistributionType.DPAR and filter_rule.dst_port_class == PC.AR: + self.distribution.add_value(filter_rule.dst_port) + + elif self.distribution_type == PortDistributionType.DPEM and filter_rule.dst_port_class == PC.EM: + self.distribution.add_value(filter_rule.dst_port) + + def compute_parameter(self): + """ + Function computes parameter from all counts of unique port values stored in instance variable distribution. + + :return: Port values distribution in string format. + """ + parameter = "" + + first = True + for port_range in self.distribution.distribution.most_common(): + + # for first port range we do not want print new line + if first: + first = False + else: + parameter += '\n' + + parameter += str(Format.decimal(port_range[1] / self.distribution.total_count)) + '\t' + str(port_range[0]) + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-' + str(self.distribution_type)[-4:].lower()) + if self.distribution.total_count != 0: + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py b/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py new file mode 100644 index 0000000..f9a76e9 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/ppc_prefixlen_distribution.py @@ -0,0 +1,92 @@ +# !/usr/bin/env python +"""Module containing definition of class PpcPrefixLenDistribution.""" + +from .distribution import Distribution +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format + + +class PpcPrefixLenDistribution(IParameter): + """ + Class representing parameter: prefix lengths distribution from rules with same port pair class (PPC). + There are total 25 PPCs, so for every group of rules with same PPC program has to create one independent instance of + class. + """ + + def __init__(self, port_pair_class): + """ + Constructor decides from which rules will be made prefix lengths distribution. Decision is made by enum value of + PPC given by parameter of constructor. + + :param port_pair_class: Enum value of PPC. + """ + self.port_pair_class = port_pair_class + """PPC of rules from which is made distribution.""" + self.distribution = dict() + """Instance variable of type dictionary. Elements in dictionary have total prefix length as key and + instance of class Distribution as value. In value of dictionary are stored counts of unique source prefix + lengths.""" + + def extract_data(self, filter_rule): + """ + Function fills dictionary (instance variable distribution) with new elements and data (counts of unique lengths). + If total prefix length extracted from filter rule is new key in dictionary, then add new element to dictionary + with this key. + Value (instance of class Distribution) of element with extracted total prefix length as key is always updated + with source prefix length of filter rule. + + :param filter_rule: FilterRule instance. + """ + if self.port_pair_class == filter_rule.get_ppc_class(): + total_length = filter_rule.src_ip_add_prefix_length + filter_rule.dst_ip_add_prefix_length + + if total_length not in self.distribution: + self.distribution[total_length] = Distribution() + + self.distribution.get(total_length).add_value(filter_rule.src_ip_add_prefix_length) + + def compute_parameter(self): + """ + Function computes parameter from all elements stored in dictionary (instance variable distribution). + + :return: Prefix lengths distribution in string format. + """ + parameter = "" + + # total count of processed rules with same PPC + rules_count = sum([value.total_count for key, value in self.distribution.items()]) + + first = True + for total_prefix_length, value in sorted(self.distribution.items()): + + # for first total prefix length we do not want print new line + if first: + first = False + else: + parameter += '\n' + + # total count of rules with same total prefix length + total_prefix_len_count = value.total_count + + parameter += str(total_prefix_length) + ',' + str(Format.decimal(total_prefix_len_count / rules_count)) + + for source_prefix_length in sorted(value.distribution): + # total count of rules with same source prefix length + src_prefix_len_count = value.distribution[source_prefix_length] + + parameter += '\t' + str(source_prefix_length) + ',' + parameter += str(Format.decimal(src_prefix_len_count / total_prefix_len_count)) + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-' + str(self.port_pair_class)[-5:].lower()) + if self.distribution: + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py new file mode 100644 index 0000000..a3f4281 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/prefix_correlation_distribution.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +"""Module containing definition of class PrefixCorrelationDistribution.""" + +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format + + +class PrefixCorrelationDistribution(IParameter): + """ + Class representing parameter: prefix correlation distribution. + Correlation means source and destination prefixes of one filter rule are continuing to be same, + in length where are both defined. + """ + + def __init__(self): + """ + Constructor initialize two instance variable as lists with zero values. + Both lists are sizes of 128. Indexes of lists are representing prefix levels. + """ + self.all_on_level = [0] * 128 + """List with counts of rules which have same source and destination prefixes until previous level.""" + self.same_on_level = [0] * 128 + """List with counts of rules which source and destination prefixes are same on level.""" + + def extract_data(self, filter_rule): + """ + Function updates counts of rules on levels (indexes) in list instance variables. + + :param filter_rule: FilterRule instance. + """ + # do not care about prefixes with wildcards + if filter_rule.src_ip_add_bin != '*' and filter_rule.dst_ip_add_bin != '*': + + # prefix length where are both prefixes defined + valid_length = PrefixCorrelationDistribution.get_smaller_prefix(filter_rule) + + i = 0 + # going through bits of prefix + for b in filter_rule.src_ip_add_bin[:valid_length]: + + self.all_on_level[i] += 1 + + # if prefixes do not continue to be same break the cycle + if b == filter_rule.dst_ip_add_bin[i]: + self.same_on_level[i] += 1 + else: + break + + i += 1 + + def compute_parameter(self): + """ + Function computes parameter from counts of rules stored in list instance variables. + + :return: Prefix correlation distribution in string format. + """ + parameter = "" + i = 1 + first = True + + for rules_count in self.all_on_level: + + # at least 32 will be printed + if i > 32 and rules_count == 0: + break + + # for first correlation we do not want print new line + if first: + first = False + else: + parameter += '\n' + + parameter += str(i) + '\t' + if rules_count == 0: + parameter += '0.00000000' + else: + parameter += str(Format.decimal(self.same_on_level[i - 1] / rules_count)) + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-pcorr') + output.print(self.compute_parameter()) + output.print('#') + + @staticmethod + def get_smaller_prefix(filter_rule): + """ + Function returns smaller one prefix length of source and destination prefixes in filter rule. + + :param filter_rule: FilterRule instance. + :return: Smaller prefix length of prefixes in filter rule. + """ + if filter_rule.src_ip_add_prefix_length > filter_rule.dst_ip_add_prefix_length: + return filter_rule.dst_ip_add_prefix_length + else: + return filter_rule.src_ip_add_prefix_length diff --git a/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py b/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py new file mode 100644 index 0000000..20f3550 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/protocol_ppc_distribution.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +"""Module containing definition of class ProtocolPpcDistribution.""" + +from .distribution import Distribution +from .interfaces.IParameter import IParameter +from ..value_formats.value_format import Format +from ..processing_rules.enums.port_pair_class import PPC + + +class ProtocolPpcDistribution(IParameter): + """ + Class representing parameter: port pair classes (PPCs) distribution over unique protocols in filter set. + """ + + def __init__(self): + """ + Constructor only initialize instance variable distribution as new instance of dictionary. + """ + self.distribution = dict() + """Instance variable of type dictionary. Elements in dictionary have protocol enum value as key and + instance of class Distribution as value.""" + + def extract_data(self, filter_rule): + """ + Function fills dictionary (instance variable distribution) with new elements and data. + If protocol extracted from filter rule is new key in dictionary, then it adds new element + with this key to dictionary. + Value (instance of class Distribution) of element with extracted protocol as key is always updated + with PPC class of filter rule. + + :param filter_rule: FilterRule instance. + """ + if filter_rule.protocol not in self.distribution: + self.distribution[filter_rule.protocol] = Distribution() + + self.distribution.get(filter_rule.protocol).add_value(filter_rule.get_ppc_class()) + + def compute_parameter(self): + """ + Function computes parameter from all elements stored in dictionary (instance variable distribution). + + :return: PPCs distribution over protocols in string format. + """ + parameter = "" + + # total count of processed protocols in all filter rules + rules_count = sum([value.total_count for key, value in self.distribution.items()]) + first = True + + for protocol, value in sorted(self.distribution.items()): + + # for first protocol we do not want print new line + if first: + first = False + else: + parameter += '\n' + + # total count of processed filter rules with specific protocol + protocol_count = value.total_count + parameter += str(protocol.value) + '\t' + str(Format.decimal(protocol_count / rules_count)) + + i = 0 + while i < 25: + ppc_distribution = value.distribution[PPC(i)] + parameter += '\t' + str(Format.decimal(ppc_distribution / protocol_count)) + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + output.print('-prots') + output.print(self.compute_parameter()) + output.print('#') diff --git a/lib/tuples_analyzer/calculation_parameters/trie_distributions.py b/lib/tuples_analyzer/calculation_parameters/trie_distributions.py new file mode 100644 index 0000000..afd1a00 --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/trie_distributions.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +"""Module containing definition of class TrieDistributions.""" + +from .enums.trie_type import TrieType +from .interfaces.IParameter import IParameter +from .trie_node import TrieNode +from ..value_formats.value_format import Format + + +class TrieDistributions(IParameter): + """ + Class representing 3 parameters gained by constructing binary prefix tree (trie). + These parameters are: distributions over prefix branching probability, skew average and prefix nesting threshold. + """ + + def __init__(self, trie_type): + """ + Constructor decides from which prefixes (source/destination) will be created trie. Decision is made by enum + value of trie type given by parameter. + + :param trie_type: Enum value of trie type. + """ + self.trie_type = trie_type + """Type of trie is telling from which prefixes is trie constructed (source/destination prefixes).""" + self.root_node = TrieNode('*') + """Root node of trie. Trie is constructed by adding new prefixes to root.""" + + def extract_data(self, filter_rule): + """ + Function is filling trie with source or destination prefixes extracted from filter rule. + + :param filter_rule: FilterRule instance. + """ + if self.trie_type == TrieType.SPT and filter_rule.src_ip_add_bin != '*': + self.root_node.add_prefix(filter_rule.src_ip_add_bin) + + elif self.trie_type == TrieType.DPT and filter_rule.dst_ip_add_bin != '*': + self.root_node.add_prefix(filter_rule.dst_ip_add_bin) + + def compute_parameter(self): + """ + Function computes parameters from constructed trie. + + :return: Computed parameters of trie distributions in string form. + """ + parameter = "" + first = True + i = 0 + + # checking if trie is not empty + if self.root_node.children: + # current level nodes + nodes = [self.root_node] + + while self.root_node.max_level > i: + + # for first level we do not want print new line + if first: + first = False + else: + parameter += '\n' + + count_1child = 0 + count_2children = 0 + # skew values on level + skew_list = [] + # nodes on next level are stored here + temp_list = [] + + for node in nodes: + if len(node.children) == 1: + count_1child += 1 + temp_list.extend(node.children) + elif len(node.children) == 2: + count_2children += 1 + temp_list.extend(node.children) + skew_list.append(node.count_skew()) + + nodes = temp_list + parameter += str(i) + '\t' + TrieDistributions.get_branching_probability(count_1child, count_2children) + parameter += '\t' + TrieDistributions.get_average_skews(skew_list) + i += 1 + + # for undefined levels of trie, lines have this format: + while i < 33: + if first: + first = False + else: + parameter += '\n' + parameter += str(i) + "\t0.00000000\t0.00000000\t0.00000000" + i += 1 + + return parameter + + def print_parameter(self, output): + """ + Function calls method compute_parameter() to compute parameter and then prints parameter to output in + ClassBench format. + + :param output: OutputPrint instance. + """ + if self.trie_type == TrieType.SPT: + output.print('-snest') + output.print(str(self.root_node.threshold)) + output.print('#') + output.print('-sskew') + output.print(self.compute_parameter()) + output.print('#') + + elif self.trie_type == TrieType.DPT: + output.print('-dnest') + output.print(str(self.root_node.threshold)) + output.print('#') + output.print('-dskew') + output.print(self.compute_parameter()) + output.print('#') + + @staticmethod + def get_branching_probability(count_1child, count_2children): + """ + Function returns probability of node having 1 child or 2 children on some level of prefix trie. + + :param count_1child: Count of nodes with 1 child on level. + + :param count_2children: Count of nodes with 2 children on level. + + :return: Probability of node having 1 child or 2 children on level. + """ + sum = count_1child + count_2children + probability_1child = Format.decimal(count_1child / sum) + probability_2children = Format.decimal(count_2children / sum) + probability = str(probability_1child) + '\t' + str(probability_2children) + return probability + + @staticmethod + def get_average_skews(skew_list): + """ + Function returns average of skews in list given by parameter. + + :param skew_list: List with skew values. + + :return: Average of skew values in list. + """ + # skew list is empty + if len(skew_list) == 0: + return '0.00000000' + + count_skews = 0 + sum_skews = 0 + + for skew in skew_list: + sum_skews += skew + count_skews += 1 + + skew_average = str(Format.decimal(sum_skews / count_skews)) + return skew_average diff --git a/lib/tuples_analyzer/calculation_parameters/trie_node.py b/lib/tuples_analyzer/calculation_parameters/trie_node.py new file mode 100644 index 0000000..bcc042e --- /dev/null +++ b/lib/tuples_analyzer/calculation_parameters/trie_node.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +"""Module containing definition of class TrieNode.""" + + +class TrieNode: + """ + Class is representing node of trie (binary prefix tree). + """ + + def __init__(self, bit): + """ + Constructor initialize node instance variable bit with value of parameter bit. + Other instance variable are initialized as empty list, zero or None. + + :param bit: Bit value. + """ + self.parent = None + """Parent of node. Only root node does not have parent.""" + self.bit = bit + """Last bit of prefix. For trie nodes can be bit value '0' or '1'. Bit of root node is '*'.""" + self.prefix = False + """Instance variable prefix is boolean type and is telling, if node is prefix or only node on path to prefix.""" + self.level = 0 + """Prefix level of node in trie.""" + self.children = [] + """List holding instances of children nodes. Trie node can have max. 2 children.""" + self.prefixes = [0, 0] + """List with prefix counts under children nodes.""" + self.threshold = 0 + """Prefix nesting threshold.""" + self.max_level = 0 + """Highest prefix level of node in trie. Only root node uses this variable while printing distributions.""" + + def get_prefix(self, prefix): + """ + Function returns instance of child node in trie represented by prefix string given by parameter. + + :param prefix: String consisting of numbers 0 and 1. + + :return: If node was found return instance of that node, otherwise return None. + """ + # trying to find node in trie, which is representing wanted string of prefix + node = self + for bit in prefix: + bit_not_found = True + + for child in node.children: + if child.bit == bit: + bit_not_found = False + node = child + break + + if bit_not_found: + return None + + # checking if found node is prefix or only path to some different prefix + if node.prefix: + return node + else: + return None + + def add_prefix(self, prefix): + """ + Function adds new prefix to trie. + Process of adding new prefix always starts from root node. + + :param prefix: String consisting of numbers 0 and 1. + """ + already_in_trie = self.get_prefix(prefix) + + # if prefix is already in trie, function only needs recalculate prefix counts of parent nodes + if already_in_trie: + TrieNode.recalculate_prefix_counts(already_in_trie) + + else: + node = self + + # search for bit in children of present node, or add a new node to trie if not found + for bit in prefix: + found_in_child = False + + for child in node.children: + if child.bit == bit: + node = child + found_in_child = True + break + + if not found_in_child: + new_node = TrieNode(bit) + new_node.level = node.level + 1 + new_node.parent = node + node.children.append(new_node) + node = new_node + + # mark new node as prefix + node.prefix = True + + # update max level of root node + if node.level > self.max_level: + self.max_level = node.level + + # recalculate prefix counts of parent nodes + TrieNode.recalculate_prefix_counts(node) + + # recalculate prefix nesting thresholds of current and parent nodes + TrieNode.recalculate_prefix_thresholds(node) + + def count_skew(self): + """ + Function computes skew of current node. It is called only on nodes, which have 2 children. + + :return: Computed skew. + """ + if self.prefixes[0] > self.prefixes[1]: + bigger = self.prefixes[0] + smaller = self.prefixes[1] + else: + bigger = self.prefixes[1] + smaller = self.prefixes[0] + + skew = 1 - smaller / bigger + return skew + + @staticmethod + def recalculate_prefix_counts(node): + """ + After adding node to trie, recalculation of prefix counts of parent nodes has to be done. + + :param node: Instance of newly added node to trie. + """ + child = node + parent = child.parent + + while parent: + if child.bit == '0': + parent.prefixes[0] += 1 + elif child.bit == '1': + parent.prefixes[1] += 1 + + child = parent + parent = child.parent + + @staticmethod + def recalculate_prefix_thresholds(node): + """ + After adding new node to trie, calculation of prefix nesting threshold of current node and recalculation of + parent thresholds has to be done. + + :param node: Instance of newly added node to trie. + """ + # finding bigger of children thresholds + bigger_child_threshold = 0 + + for child in node.children: + child_threshold = 0 + + if child.prefix: + child_threshold += 1 + + child_threshold += child.threshold + + if child_threshold > bigger_child_threshold: + bigger_child_threshold = child_threshold + + # setting threshold of added node + node.threshold = bigger_child_threshold + + # recalculate prefix nesting thresholds of parent nodes + child = node + parent = child.parent + threshold = bigger_child_threshold + 1 + + while parent: + if threshold > parent.threshold: + parent.threshold = threshold + else: + break + + if parent.prefix: + threshold += 1 + + child = parent + parent = child.parent diff --git a/lib/tuples_analyzer/examples/formats/custom1.format b/lib/tuples_analyzer/examples/formats/custom1.format new file mode 100644 index 0000000..0afa4aa --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/custom1.format @@ -0,0 +1 @@ +PROTOCOL from SRC_IP SRC_PORT to DST_IP DST_PORT diff --git a/lib/tuples_analyzer/examples/formats/custom2.format b/lib/tuples_analyzer/examples/formats/custom2.format new file mode 100644 index 0000000..6259e4d --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/custom2.format @@ -0,0 +1 @@ +PROTOCOL destination DST_IP ip-port? DST_PORT? source SRC_IP ip-port? SRC_PORT? diff --git a/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format b/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format new file mode 100644 index 0000000..33aa4d3 --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/custom_with_ipv6.format @@ -0,0 +1 @@ +rule NUMBER WILDCARD PROTOCOL source? SRC_IP? destination? DST_IP? destination-port DST_PORT? diff --git a/lib/tuples_analyzer/examples/formats/ipfw.format b/lib/tuples_analyzer/examples/formats/ipfw.format new file mode 100644 index 0000000..86004fa --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/ipfw.format @@ -0,0 +1 @@ +ipfw add WILDCARD PROTOCOL? from SRC_IP? SRC_PORT? to DST_IP? DST_PORT? \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/formats/iptables.format b/lib/tuples_analyzer/examples/formats/iptables.format new file mode 100644 index 0000000..6d1933f --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/iptables.format @@ -0,0 +1 @@ +iptables WILDCARD INPUT -s? SRC_IP? -d? DST_IP? -p? PROTOCOL? --sport? SRC_PORT? --dport? DST_PORT? -j WILDCARD \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/formats/openflow.format b/lib/tuples_analyzer/examples/formats/openflow.format new file mode 100644 index 0000000..0daaf50 --- /dev/null +++ b/lib/tuples_analyzer/examples/formats/openflow.format @@ -0,0 +1,2 @@ +nw_proto=PROTOCOL, nw_src?=SRC_IP?, nw_dst?=DST_IP?, tp_src?=SRC_PORT?, tp_dst?=DST_PORT? + diff --git a/lib/tuples_analyzer/examples/sets/custom1.set b/lib/tuples_analyzer/examples/sets/custom1.set new file mode 100644 index 0000000..568440e --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/custom1.set @@ -0,0 +1,58 @@ +any from 147.229.35.0/24 any to 147.229.37.9 any +tcp from any any to 147.229.37.9 443 +tcp from 147.229.32.0/20 any to 147.229.37.9/32 80 +tcp from 147.229.82.0/23 any to 147.229.37.9/32 80 +tcp from 147.229.84.0/22 any to 147.229.37.9/32 80 +tcp from 147.229.128.0/20 any to 147.229.37.9/32 80 +tcp from any any to 147.229.37.9/32 any +any from 147.229.35.0/24 any to 147.229.87.12/30 any +any from 147.229.37.0/24 any to 147.229.87.12/30 any +any from 147.229.87.0/24 any to 147.229.87.12/30 any +any from 147.229.128.248/29 any to 147.229.87.12/30 any +any from any any to 147.229.87.12/30 any +any from 147.229.35.0/24 any to 147.229.128.0/24 any +any from 147.229.37.0/24 any to 147.229.128.0/24 any +any from 147.229.128.0/24 any to 147.229.128.0/24 any +any from 147.229.87.12/30 any to 147.229.128.248/29 any +any from 147.229.131.230/32 any to 147.229.128.64/28 any +any from 147.229.0.0/16 any to 147.229.128.79/32 any +any from 147.229.153.0/24 any to 147.229.128.128/28 any +any from 147.229.0.0/16 any to 147.229.128.248/29 any +any from any any to 147.229.128.0/24 any +any from 147.229.35.0/24 any to 147.229.131.240/28 any +any from 147.229.37.0/24 any to 147.229.131.240/28 any +any from 147.229.185.0/24 any to 147.229.131.240/28 any +tcp from 147.229.131.240/28 any to any any +tcp from any any to 147.229.131.240/28 any +any from 147.229.34.0/23 any to 147.229.34.0/24 any +any from 147.229.36.0/23 any to 147.229.34.0/24 any +any from any any to 147.229.34.0/28 any +any from any any to 147.229.34.152/29 any +tcp from any any to 147.229.34.0/24 any +tcp from any any to 147.229.37.10/31 25 +tcp from any any to 147.229.37.12/31 25 +tcp from 147.229.32.0/20 any to any 25 +tcp from 147.229.82.0/23 any to any 25 +tcp from 147.229.84.0/22 any to any 25 +tcp from 147.229.128.0/20 any to any 25 +tcp from any any to 147.229.32.0/20 25 +tcp from any any to 147.229.82.0/23 25 +tcp from any any to 147.229.84.0/22 25 +tcp from any any to 147.229.128.0/20 25 +tcp from 147.229.0.0/16 any to 147.229.37.128/25 80 +tcp from any any to 147.229.37.128/25 80 +tcp from any any to 147.229.35.90/32 any +any from 147.229.32.0/20 any to 147.229.35.90/32 any +any from 147.229.2.218/31 any to 147.229.131.240/28 any +any from 147.229.131.243/32 any to 147.229.2.218/31 any +any from 147.229.2.218/31 any to 147.229.131.243/32 any +any from 147.229.131.243 any to any any +any from 147.229.131.230 any to 147.229.128.80/28 any +tcp from 147.229.137.176 any to 147.229.131.244/30 80 +tcp from 62.84.154.90/32 any to 147.229.131.244/30 80 +any from 147.229.43.128/28 any to 147.229.43.0/24 any +any from 147.229.43.144/30 any to 147.229.43.0/24 any +any from 147.229.43.128/28 any to 147.229.37.0/25 any +any from 147.229.43.144/30 any to 147.229.37.0/25 any +any from 147.229.43.128/28 any to any any +any from 147.229.43.144/30 any to any any diff --git a/lib/tuples_analyzer/examples/sets/custom2.set b/lib/tuples_analyzer/examples/sets/custom2.set new file mode 100644 index 0000000..2f10acc --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/custom2.set @@ -0,0 +1,58 @@ +ip destination 147.229.37.9/32 source 147.229.35.0/24 permit ports any precedence 101 +tcp destination 147.229.37.9/32 ip-port 443 source any ip-port any permit ports any precedence 111 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.32.0/20 ip-port any permit ports any precedence 121 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.82.0/23 ip-port any permit ports any precedence 122 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.84.0/22 ip-port any permit ports any precedence 123 +tcp destination 147.229.37.9/32 ip-port 80 source 147.229.128.0/20 ip-port any permit ports any precedence 124 +tcp destination 147.229.37.9/32 ip-port any source any ip-port any permit-established ports any precedence 141 +ip destination 147.229.87.12/30 source 147.229.35.0/24 permit ports any precedence 201 +ip destination 147.229.87.12/30 source 147.229.37.0/24 permit ports any precedence 202 +ip destination 147.229.87.12/30 source 147.229.87.0/24 permit ports any precedence 203 +ip destination 147.229.87.12/30 source 147.229.128.248/29 permit ports any precedence 204 +ip destination 147.229.87.12/30 source any deny ports any precedence 241 +ip destination 147.229.128.0/24 source 147.229.35.0/24 permit ports any precedence 301 +ip destination 147.229.128.0/24 source 147.229.37.0/24 permit ports any precedence 302 +ip destination 147.229.128.0/24 source 147.229.128.0/24 permit ports any precedence 303 +ip destination 147.229.128.248/29 source 147.229.87.12/30 permit ports any precedence 311 +ip destination 147.229.128.64/28 source 147.229.131.230/32 permit ports any precedence 321 +ip destination 147.229.128.79/32 source 147.229.0.0/16 permit ports any precedence 322 +ip destination 147.229.128.128/28 source 147.229.153.0/24 permit ports any precedence 331 +ip destination 147.229.128.248/29 source 147.229.0.0/16 permit ports any precedence 341 +ip destination 147.229.128.0/24 source any deny ports any precedence 361 +ip destination 147.229.131.240/28 source 147.229.35.0/24 permit ports any precedence 401 +ip destination 147.229.131.240/28 source 147.229.37.0/24 permit ports any precedence 402 +ip destination 147.229.131.240/28 source 147.229.185.0/24 permit ports any precedence 403 +tcp destination any ip-port any source 147.229.131.240/28 ip-port any permit ports any precedence 411 +tcp destination 147.229.131.240/28 ip-port any source any ip-port any permit-established ports any precedence 441 +ip destination 147.229.34.0/24 source 147.229.34.0/23 permit ports any precedence 501 +ip destination 147.229.34.0/24 source 147.229.36.0/23 permit ports any precedence 502 +ip destination 147.229.34.0/28 source any permit ports any precedence 511 +ip destination 147.229.34.152/29 source any permit ports any precedence 512 +tcp destination 147.229.34.0/24 ip-port any source any ip-port any permit-established ports any precedence 541 +tcp destination 147.229.37.10/31 ip-port 25 source any ip-port any permit ports any precedence 601 +tcp destination 147.229.37.12/31 ip-port 25 source any ip-port any permit ports any precedence 602 +tcp destination any ip-port 25 source 147.229.32.0/20 ip-port any permit ports any precedence 621 +tcp destination any ip-port 25 source 147.229.82.0/23 ip-port any permit ports any precedence 622 +tcp destination any ip-port 25 source 147.229.84.0/22 ip-port any permit ports any precedence 623 +tcp destination any ip-port 25 source 147.229.128.0/20 ip-port any permit ports any precedence 624 +tcp destination 147.229.32.0/20 ip-port 25 source any ip-port any deny ports any precedence 641 +tcp destination 147.229.82.0/23 ip-port 25 source any ip-port any deny ports any precedence 642 +tcp destination 147.229.84.0/22 ip-port 25 source any ip-port any deny ports any precedence 643 +tcp destination 147.229.128.0/20 ip-port 25 source any ip-port any deny ports any precedence 644 +tcp destination 147.229.37.128/25 ip-port 80 source 147.229.0.0/16 ip-port any permit ports any precedence 191 +tcp destination 147.229.37.128/25 ip-port 80 source any ip-port any deny ports any precedence 192 +tcp destination 147.229.35.90/32 ip-port any source any ip-port any permit-established ports any precedence 709 +ip destination 147.229.35.90/32 source 147.229.32.0/20 permit ports any precedence 701 +ip destination 147.229.131.240/28 source 147.229.2.218/31 permit ports any precedence 404 +ip destination 147.229.2.218/31 source 147.229.131.243/32 permit ports any precedence 390 +ip destination 147.229.131.243/32 source 147.229.2.218/31 permit ports any precedence 391 +ip destination any source 147.229.131.243/32 permit ports any precedence 393 +ip destination 147.229.128.80/28 source 147.229.131.230/32 permit ports any precedence 323 +tcp destination 147.229.131.244/30 ip-port 80 source 147.229.137.176/32 ip-port any permit ports any precedence 421 +tcp destination 147.229.131.244/30 ip-port 80 source 62.84.154.90/32 ip-port any permit ports any precedence 422 +ip destination 147.229.43.0/24 source 147.229.43.128/28 permit ports any precedence 551 +ip destination 147.229.43.0/24 source 147.229.43.144/30 permit ports any precedence 552 +ip destination 147.229.37.0/25 source 147.229.43.128/28 permit ports any precedence 553 +ip destination 147.229.37.0/25 source 147.229.43.144/30 permit ports any precedence 554 +ip destination any source 147.229.43.128/28 deny ports any precedence 561 +ip destination any source 147.229.43.144/30 deny ports any precedence 562 diff --git a/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set b/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set new file mode 100644 index 0000000..cddcdaa --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/custom_with_ipv6.set @@ -0,0 +1,6 @@ +rule 1 permit tcp source 147.240.1.0/24 destination-port 1 +rule 2 permit tcp destination 147.10.10.1/32 destination-port smtp +rule 3 permit udp source fd6d:fa5:24bc:a286::/64 destination-port 2:10 +rule 4 deny udp destination 2001:ABC:1230::/48 destination-port 11 +rule 5 permit tcp destination 2001:ABC:1230::1234:123/128 destination-port 11 +rule 6 permit tcp source 2001:67B:1220:F000::/52 destination 2001:FED:1230::/48 destination-port 12:300 diff --git a/lib/tuples_analyzer/examples/sets/ipfw.set b/lib/tuples_analyzer/examples/sets/ipfw.set new file mode 100644 index 0000000..6ca835d --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/ipfw.set @@ -0,0 +1,4 @@ +ipfw add allow tcp from to 10.0.0.0/24 80 +ipfw add accept udp from to 192.0.0.14 +ipfw add deny any from to 5000:5100 +ipfw add drop from 443 to \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/sets/iptables.set b/lib/tuples_analyzer/examples/sets/iptables.set new file mode 100644 index 0000000..efce55c --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/iptables.set @@ -0,0 +1,5 @@ +iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport 0:1023 -j ACCEPT +iptables -A INPUT -s 128.0.0.0/24 -p tcp --sport all -j ACCEPT +iptables -I INPUT -s 192.0.0.1 -p udp --dport 80 -j DROP +iptables -I INPUT -s 192.0.0.0/3 -p udp --dport 1024:65535 -j DROP +iptables -I INPUT -s 192.0.0.0/3 -p udp --dport 5000:5100 -j ACCEPT \ No newline at end of file diff --git a/lib/tuples_analyzer/examples/sets/openflow.set b/lib/tuples_analyzer/examples/sets/openflow.set new file mode 100644 index 0000000..c214288 --- /dev/null +++ b/lib/tuples_analyzer/examples/sets/openflow.set @@ -0,0 +1,58 @@ +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.37.9/32 +nw_proto=6 ,nw_dst=147.229.37.9/32 ,tp_dst=443 +nw_proto=6 ,nw_src=147.229.32.0/20 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.82.0/23 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.84.0/22 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_src=147.229.128.0/20 ,nw_dst=147.229.37.9/32 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.37.9/32 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.87.0/24 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.128.248/29 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_dst=147.229.87.12/30 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.128.0/24 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.87.12/30 ,nw_dst=147.229.128.248/29 +nw_proto=0 ,nw_src=147.229.131.230/32 ,nw_dst=147.229.128.64/28 +nw_proto=0 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.128.79/32 +nw_proto=0 ,nw_src=147.229.153.0/24 ,nw_dst=147.229.128.128/28 +nw_proto=0 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.128.248/29 +nw_proto=0 ,nw_dst=147.229.128.0/24 +nw_proto=0 ,nw_src=147.229.35.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.37.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.185.0/24 ,nw_dst=147.229.131.240/28 +nw_proto=6 ,nw_src=147.229.131.240/28 +nw_proto=6 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.34.0/23 ,nw_dst=147.229.34.0/24 +nw_proto=0 ,nw_src=147.229.36.0/23 ,nw_dst=147.229.34.0/24 +nw_proto=0 ,nw_dst=147.229.34.0/28 +nw_proto=0 ,nw_dst=147.229.34.152/29 +nw_proto=6 ,nw_dst=147.229.34.0/24 +nw_proto=6 ,nw_dst=147.229.37.10/31 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.37.12/31 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.32.0/20 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.82.0/23 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.84.0/22 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.128.0/20 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.32.0/20 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.82.0/23 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.84.0/22 ,tp_dst=25 +nw_proto=6 ,nw_dst=147.229.128.0/20 ,tp_dst=25 +nw_proto=6 ,nw_src=147.229.0.0/16 ,nw_dst=147.229.37.128/25 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.37.128/25 ,tp_dst=80 +nw_proto=6 ,nw_dst=147.229.35.90/32 +nw_proto=0 ,nw_src=147.229.32.0/20 ,nw_dst=147.229.35.90/32 +nw_proto=0 ,nw_src=147.229.2.218/31 ,nw_dst=147.229.131.240/28 +nw_proto=0 ,nw_src=147.229.131.243/32 ,nw_dst=147.229.2.218/31 +nw_proto=0 ,nw_src=147.229.2.218/31 ,nw_dst=147.229.131.243/32 +nw_proto=0 ,nw_src=147.229.131.243/32 +nw_proto=0 ,nw_src=147.229.131.230/32 ,nw_dst=147.229.128.80/28 +nw_proto=6 ,nw_src=147.229.137.176/32 ,nw_dst=147.229.131.244/30 ,tp_dst=80 +nw_proto=6 ,nw_src=62.84.154.90/32 ,nw_dst=147.229.131.244/30 ,tp_dst=80 +nw_proto=0 ,nw_src=147.229.43.128/28 ,nw_dst=147.229.43.0/24 +nw_proto=0 ,nw_src=147.229.43.144/30 ,nw_dst=147.229.43.0/24 +nw_proto=0 ,nw_src=147.229.43.128/28 ,nw_dst=147.229.37.0/25 +nw_proto=0 ,nw_src=147.229.43.144/30 ,nw_dst=147.229.37.0/25 +nw_proto=0 ,nw_src=147.229.43.128/28 +nw_proto=0 ,nw_src=147.229.43.144/30 diff --git a/lib/tuples_analyzer/printing_output/__init__.py b/lib/tuples_analyzer/printing_output/__init__.py new file mode 100644 index 0000000..3e1765d --- /dev/null +++ b/lib/tuples_analyzer/printing_output/__init__.py @@ -0,0 +1 @@ +"""Package with classes for printing output data to different directions.""" diff --git a/lib/tuples_analyzer/printing_output/enums/__init__.py b/lib/tuples_analyzer/printing_output/enums/__init__.py new file mode 100644 index 0000000..7462f7d --- /dev/null +++ b/lib/tuples_analyzer/printing_output/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while printing output data.""" diff --git a/lib/tuples_analyzer/printing_output/enums/output_direction.py b/lib/tuples_analyzer/printing_output/enums/output_direction.py new file mode 100644 index 0000000..a52955c --- /dev/null +++ b/lib/tuples_analyzer/printing_output/enums/output_direction.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class OutputDirection.""" + +from enum import Enum + + +class OutputDirection(Enum): + """ + Enum for every possible output direction of program. + """ + + STDOUT = 0 + """Standard output.""" + FILE = 1 + """Output to file.""" diff --git a/lib/tuples_analyzer/printing_output/output_print.py b/lib/tuples_analyzer/printing_output/output_print.py new file mode 100644 index 0000000..bee605b --- /dev/null +++ b/lib/tuples_analyzer/printing_output/output_print.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +"""Module containing definition of class OutputDirection.""" + +import os +from .enums.output_direction import OutputDirection +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class OutputPrint: + """ + Class used to print computed parameters in same way to different directions (STDOUT or to file). + """ + + def __init__(self, output_file_path): + """ + Constructor is calling function decide_direction() to initialize instance variables. + + :param output_file_path: Path to file, where user wants to save computed parameters. + """ + self.output_direction = None + """Printing output direction.""" + self.output_file_path = None + """Path to file, where user wants to save computed parameters.""" + self.decide_direction(output_file_path) + + def decide_direction(self, output_file_path): + """ + Function decides, where will be printed output. + If parameter output_file_path is None, output will be printed on STDOUT, + otherwise output will be printed to file specified by parameter. + + :param output_file_path: Path to file, where user wants to save computed parameters. + + :return: If file where user wants to save computed parameters already exists or is not at least empty, + then program prints error message and exits with error code 40. + """ + if output_file_path is None: + self.output_direction = OutputDirection.STDOUT + + else: + if not os.path.isfile(output_file_path) or os.stat(output_file_path).st_size == 0: + try: + with open(output_file_path, 'a+'): + pass + + except EnvironmentError: + ErrorProcess.process_error(Error.CREATING_FILE_ERROR, + f'Wrong path to file where you want to save computed parameters: ' + f'\'{output_file_path}\'.') + self.output_direction = OutputDirection.FILE + self.output_file_path = output_file_path + else: + ErrorProcess.process_error(Error.CREATING_FILE_ERROR, + f'File where you want to save computed parameters: ' + f'\'{output_file_path}\' ' + f'already exists.') + + def print(self, message): + """ + Function prints message to output direction specified in instance variable output_direction. + + :param message: String message. + """ + if self.output_direction == OutputDirection.STDOUT: + print(message) + else: + with open(self.output_file_path, 'a+') as the_file: + the_file.write(str(message) + '\n') diff --git a/lib/tuples_analyzer/processing_arguments/__init__.py b/lib/tuples_analyzer/processing_arguments/__init__.py new file mode 100644 index 0000000..14e8641 --- /dev/null +++ b/lib/tuples_analyzer/processing_arguments/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing arguments from command line.""" diff --git a/lib/tuples_analyzer/processing_arguments/processed_arguments.py b/lib/tuples_analyzer/processing_arguments/processed_arguments.py new file mode 100644 index 0000000..0d6972c --- /dev/null +++ b/lib/tuples_analyzer/processing_arguments/processed_arguments.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +"""Module containing definition of class ProcessedArguments.""" + +import sys +import getopt +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class ProcessedArguments: + """ + Class for processing and storing command line arguments from user. + """ + + def __init__(self): + """ + Constructor is calling function process_arguments() to process arguments and + to initialize instance variables with argument values. + """ + self.rules_path = None + """Path to file with filter rules.""" + self.format_path = None + """Path to file with format of filter rules.""" + self.output_path = None + """Path to file, where user wants to save computed parameters.""" + self.is_stderr_on = False + """Variable telling, if printing error logs while parsing filter rules is enabled.""" + self.process_arguments() + + def process_arguments(self): + """ + Function processing command line arguments of program. + + :return: If it processed wrong or no arguments, it prints error message and exits with error code 10. + + If it processed argument -h, it calls function usage() and exit. + + If it processed both mandatory arguments: -r and -f with specified path to file with rules and + path to file with format of rules, then it initializes instance variables. + """ + argv = sys.argv[1:] + + rules_path = None + format_path = None + output_path = None + is_stderr_on = False + + try: + opts, args = getopt.getopt(argv, "r:f:o:lh", ["rules=", "format=", "output=", "logs", "help"]) + except getopt.GetoptError as err: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'{err}') + + if len(opts) < 1 or len(opts) > 4 or len(args) > 0: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'Wrong or no arguments selected.') + + for o, a in opts: + if o in ("-h", "--help"): + ProcessedArguments.print_manual() + sys.exit() + elif o in ("-r", "--rules"): + rules_path = a + elif o in ("-f", "--format"): + format_path = a + elif o in ("-o", "--output"): + output_path = a + elif o in ("-l", "--logs"): + is_stderr_on = True + + if rules_path is None or format_path is None: + ErrorProcess.process_error(Error.ARGUMENTS_ERROR, f'Missing argument -r or -f.') + else: + self.rules_path = rules_path + self.format_path = format_path + self.output_path = output_path + self.is_stderr_on = is_stderr_on + + @staticmethod + def print_manual(): + """ + Function prints manual of program. + """ + print('1.PROGRAM:\n\ttuples_analyzer\n\n' + '2.FUNCTION:\n\tProgram creates parameter file from statistics and distributions of real filter set.\n\t' + 'File with format of rules is needed for processing filter rules.\n\t' + 'Computed parameters are then used to generate synthetic filter set by tools ClassBench and ' + 'ClassBench-ng. \n\tFormat of rules and examples usages of program are described in README file.\n\n' + '3.USAGE:\n\tpython3 -m tuples_analyzer -r -f [-o -l -h]' + '\n\n' + '4.MANDATORY ARGUMENTS:\n' + '\t-r rules_file | --rules=rules_file\t\tspecify path to file with filter rules\n' + '\t-f format_file | --format=format_file\t\tspecify path to file with format of rules\n\n' + '5.OPTIONAL ARGUMENTS:\n' + '\t-o output_file | --output=output_file\t\tspecify path to file, which will be created\n' + '\t\t\t\t\t\t\tto store computed parameters\n\n' + '\t-l | --logs\t\t\t\t\tprinting error logs during computation is enabled\n' + '\t-h | --help\t\t\t\t\tdisplay this manual\n' + '\n6.AUTHOR:\n\tJozef Sabo') diff --git a/lib/tuples_analyzer/processing_errors/__init__.py b/lib/tuples_analyzer/processing_errors/__init__.py new file mode 100644 index 0000000..d1b98d4 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/__init__.py @@ -0,0 +1 @@ +"""Package with classes to correctly end program while error occurred and for printing error logs to stderr.""" diff --git a/lib/tuples_analyzer/processing_errors/enums/Error.py b/lib/tuples_analyzer/processing_errors/enums/Error.py new file mode 100644 index 0000000..6610337 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/enums/Error.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Module containing definition of enum class Error.""" + +from enum import Enum + + +class Error(Enum): + """ + Enum for every possible error, which can occur in program. + """ + + ARGUMENTS_ERROR = 10 + """Error which occurred while processing command line arguments.""" + FILE_OPENING_ERROR = 20 + """Error which occurred while opening file.""" + RULE_FORMAT_ERROR = 30 + """Error which occurred while processing file with format of rules.""" + CREATING_FILE_ERROR = 40 + """Error which occurred while creating file for storing output parameters.""" + NO_VALUE_FILTER_SET_ERROR = 50 + """Error telling that file with filter rules has no valuable content in it.""" diff --git a/lib/tuples_analyzer/processing_errors/enums/__init__.py b/lib/tuples_analyzer/processing_errors/enums/__init__.py new file mode 100644 index 0000000..cf8e378 --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while processing errors.""" diff --git a/lib/tuples_analyzer/processing_errors/error_process.py b/lib/tuples_analyzer/processing_errors/error_process.py new file mode 100644 index 0000000..bc654bf --- /dev/null +++ b/lib/tuples_analyzer/processing_errors/error_process.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +"""Module containing definition of class ErrorProcess.""" + +import sys +from .enums.Error import Error + + +class ErrorProcess: + """ + Class used for correctly ending program while different type of error occurred. + Class also used for printing error logs to stderr. + """ + + @staticmethod + def print_warning(message): + """ + Function prints warning log message to stderr. + + :param message: Message which will be printed to stderr. + """ + sys.stderr.write(f'{sys.argv[0]}:\nWARNING: {message}\n\n') + + @staticmethod + def process_error(error, message=''): + """ + Function prints error message and exits program with value of parameter error. + + :param error: Enum value representing error which occurred. + + :param message: Message which will be printed to stderr. + """ + if error == Error.ARGUMENTS_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: {message}\nTry \'python3 -m filter_rule_analyzer --help\'.\n') + + elif error == Error.FILE_OPENING_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: Error while opening file with path: \'{message}\'.\n') + + elif error == Error.RULE_FORMAT_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: Error while processing file with format: \'{message}\'.\n') + + elif error == Error.CREATING_FILE_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: {message}\n') + + elif error == Error.NO_VALUE_FILTER_SET_ERROR: + sys.stderr.write(f'{sys.argv[0]}:\nERROR: File with filter rules is empty or has not valuable content.\n') + + exit(error.value) diff --git a/lib/tuples_analyzer/processing_files/__init__.py b/lib/tuples_analyzer/processing_files/__init__.py new file mode 100644 index 0000000..2a703be --- /dev/null +++ b/lib/tuples_analyzer/processing_files/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing data from files.""" diff --git a/lib/tuples_analyzer/processing_files/processing_file_helper.py b/lib/tuples_analyzer/processing_files/processing_file_helper.py new file mode 100644 index 0000000..993b09b --- /dev/null +++ b/lib/tuples_analyzer/processing_files/processing_file_helper.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +"""Module containing definition of class ProcessingFileHelper.""" + +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess + + +class ProcessingFileHelper: + """ + Class contains only static functions to help with processing of files. + """ + + @staticmethod + def create_lines_generator(file_path): + """ + Function creates generator of lines from file. + + :param file_path: Path to file. + + :return: Generator of lines in file. + If function can not open file, it prints error message and exits with error code 20. + """ + try: + with open(file_path, 'r') as file: + for line in file: + yield line.strip() + except EnvironmentError: + ErrorProcess.process_error(Error.FILE_OPENING_ERROR, file_path) + + @staticmethod + def get_format(file_path): + """ + Function processes file with format of rules and returns format from first line of file. + + :param file_path: Path to file with format of rule. + + :return: First line of file. + If line is empty, it prints error message and exits with error code 30. + """ + rule_format = '' + + for line in ProcessingFileHelper.create_lines_generator(file_path): + rule_format = line + break + + if not rule_format or rule_format.isspace(): + ErrorProcess.process_error(Error.RULE_FORMAT_ERROR, file_path) + else: + return rule_format diff --git a/lib/tuples_analyzer/processing_rules/__init__.py b/lib/tuples_analyzer/processing_rules/__init__.py new file mode 100644 index 0000000..69d6693 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/__init__.py @@ -0,0 +1 @@ +"""Package with classes for processing filter rules from filter set file into generator of FilterRule instances.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/__init__.py b/lib/tuples_analyzer/processing_rules/enums/__init__.py new file mode 100644 index 0000000..8bdc644 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/__init__.py @@ -0,0 +1 @@ +"""Package with enum classes used while processing filter rules into generator of FilterRule instances.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py new file mode 100644 index 0000000..ad48e64 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_location.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartLocation.""" + +from enum import Enum + + +class FilterRulePartLocation(Enum): + """ + Enum for every possible 'location' of these filter rule parameters: port and ip address. + """ + + SOURCE = 0 + """Source location of filter rule parameter.""" + DESTINATION = 1 + """Destination location of filter rule parameter.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py new file mode 100644 index 0000000..f52ac94 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_processing_result.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartProcessingResult.""" + +from enum import Enum + + +class FilterRulePartProcessingResult(Enum): + """ + Enum for every possible result scenario while processing filter rule part into FilterRule instance. + """ + + MANDATORY_PART_PROCESSED = 0 + """Mandatory part of filter rule was processed.""" + OPTIONAL_PART_PROCESSED = 1 + """Optional part of filter rule was processed.""" + MANDATORY_PART_MISSING = 2 + """Mandatory part of filter rule is missing.""" + OPTIONAL_PART_MISSING = 3 + """Optional part of filter rule is missing.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py new file mode 100644 index 0000000..ee15c74 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/filter_rule_part_type.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +"""Module containing definition of enum class FilterRulePartType.""" + +from enum import Enum + + +class FilterRulePartType(Enum): + """ + Enum for every possible type of filter rule part. One word of filter rule is considered as filter part. + """ + + ANY = 0 + """Representation of wildcard value.""" + PROTOCOL = 1 + """Network protocol abbreviation.""" + IPV4_ADDRESS = 2 + """IPv4 address without mask.""" + IPV4_ADDRESS_MASK = 3 + """IPv4 address with mask.""" + PORT = 4 + """Port value.""" + PORT_RANGE = 5 + """Port range value.""" + NUMBER = 6 + """Number bigger than 65535 (not used for computation parameters e.g. precedence number).""" + KEYWORD = 7 + """Word which is part of rule format definition e.g. from, to.""" + WORD = 8 + """Every other value.""" + IPV6_ADDRESS = 9 + """IPv6 address without mask.""" + IPV6_ADDRESS_MASK = 10 + """IPv6 address with mask.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py b/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py new file mode 100644 index 0000000..c486b90 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/ordered_enum.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +"""Module containing definition of enum class OrderedEnum.""" + +from enum import Enum + + +class OrderedEnum(Enum): + """ + Class inheriting from base enum class and making enum values comparable. + """ + + def __ge__(self, other): + if self.__class__ is other.__class__: + return self.value >= other.value + + def __gt__(self, other): + if self.__class__ is other.__class__: + return self.value > other.value + + def __le__(self, other): + if self.__class__ is other.__class__: + return self.value <= other.value + + def __lt__(self, other): + if self.__class__ is other.__class__: + return self.value < other.value diff --git a/lib/tuples_analyzer/processing_rules/enums/port_class.py b/lib/tuples_analyzer/processing_rules/enums/port_class.py new file mode 100644 index 0000000..a5ff3bb --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/port_class.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PC.""" + +from enum import Enum + + +class PC(Enum): + """ + Enum for every possible port class (PC). + """ + + WC = 0 + """Wildcard.""" + LO = 1 + """Port range 0:1023.""" + HI = 2 + """Port range 1024:65535.""" + EM = 3 + """Exact match e.g port 80.""" + AR = 4 + """Arbitrary range e.g. port range 50000:51000.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py b/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py new file mode 100644 index 0000000..eb315c5 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/port_pair_class.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +"""Module containing definition of enum class PPC.""" + +from enum import Enum + + +class PPC(Enum): + """ + Enum for every possible port pair class (PPC). + PPC is pair consisting of source and destination port classes. + There are 25 total PPC for every combination of source and destination port classes. + """ + + WC_WC = 0 + """Source port class is WC and destination port class is WC.""" + WC_HI = 1 + """Source port class is WC and destination port class is HI.""" + HI_WC = 2 + """Source port class is HI and destination port class is WC.""" + HI_HI = 3 + """Source port class is HI and destination port class is HI.""" + WC_LO = 4 + """Source port class is WC and destination port class is LO.""" + LO_WC = 5 + """Source port class is LO and destination port class is WC.""" + HI_LO = 6 + """Source port class is HI and destination port class is LO.""" + LO_HI = 7 + """Source port class is LO and destination port class is HI.""" + LO_LO = 8 + """Source port class is LO and destination port class is LO.""" + WC_AR = 9 + """Source port class is WC and destination port class is AR.""" + AR_WC = 10 + """Source port class is AR and destination port class is WC.""" + HI_AR = 11 + """Source port class is HI and destination port class is AR.""" + AR_HI = 12 + """Source port class is AR and destination port class is HI.""" + WC_EM = 13 + """Source port class is WC and destination port class is EM.""" + EM_WC = 14 + """Source port class is EM and destination port class is WC.""" + HI_EM = 15 + """Source port class is HI and destination port class is EM.""" + EM_HI = 16 + """Source port class is EM and destination port class is HI.""" + LO_AR = 17 + """Source port class is LO and destination port class is AR.""" + AR_LO = 18 + """Source port class is AR and destination port class is LO.""" + LO_EM = 19 + """Source port class is LO and destination port class is EM.""" + EM_LO = 20 + """Source port class is EM and destination port class is LO.""" + AR_AR = 21 + """Source port class is AR and destination port class is AR.""" + AR_EM = 22 + """Source port class is AR and destination port class is EM.""" + EM_AR = 23 + """Source port class is EM and destination port class is AR.""" + EM_EM = 24 + """Source port class is EM and destination port class is EM.""" diff --git a/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py b/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py new file mode 100644 index 0000000..d52a92f --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/enums/protocol_numbers.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""Module containing definition of enum class Protocol.""" + +from .ordered_enum import OrderedEnum + + +class Protocol(OrderedEnum): + """ + Enum for every protocol located in ClassBench example parameter files. + Enum values are given by protocol number definition by IANA. + """ + + ANY = 0 + """Wildcard protocol.""" + ICMP = 1 + """Internet Control Message.""" + IGMP = 2 + """Internet Group Management.""" + GGP = 3 + """Gateway-to-Gateway.""" + ST = 5 + """Stream.""" + TCP = 6 + """Transmission Control.""" + EGP = 8 + """Exterior Gateway Protocol.""" + UDP = 17 + """User Datagram.""" + GRE = 47 + """Generic Routing Encapsulation.""" + ESP = 50 + """Encap Security Payload.""" + AH = 51 + """Authentication Header.""" + EIGRP = 88 + """EIGRP.""" + OSPFIGP = 89 + """OSPFIGP.""" diff --git a/lib/tuples_analyzer/processing_rules/filter_rule.py b/lib/tuples_analyzer/processing_rules/filter_rule.py new file mode 100644 index 0000000..f4dfc9d --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/filter_rule.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python +"""Module containing definition of class FilterRule.""" + +from .enums.filter_rule_part_location import FilterRulePartLocation +from .enums.port_class import PC +from .enums.port_pair_class import PPC +from .enums.protocol_numbers import Protocol +import ipaddress + + +class FilterRule: + """ + Class representing filter rule. + """ + + def __init__(self): + """ + Constructor initialize all filter rule attributes with wildcard values. + """ + self.protocol = Protocol.ANY + """Protocol number defined by IANA.""" + self.src_port_class = PC.WC + """Source port class.""" + self.src_port = None + """Source port value.""" + self.dst_port_class = PC.WC + """Destination port class.""" + self.dst_port = None + """Destination port value.""" + self.src_ip_add_bin = '*' + """Source IP address in binary form.""" + self.src_ip_add_prefix_length = 0 + """Source IP address prefix length.""" + self.dst_ip_add_bin = '*' + """Destination IP address in binary form.""" + self.dst_ip_add_prefix_length = 0 + """Destination IP address prefix length.""" + + def get_ppc_class(self): + """ + Function returns enum value representing port pair class (PPC) of this filter rule. + + :return: Enum value representing PPC of this filter rule. + """ + if self.src_port_class == PC.WC and self.dst_port_class == PC.WC: + return PPC.WC_WC + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.HI: + return PPC.WC_HI + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.WC: + return PPC.HI_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.HI: + return PPC.HI_HI + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.LO: + return PPC.WC_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.WC: + return PPC.LO_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.LO: + return PPC.HI_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.HI: + return PPC.LO_HI + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.LO: + return PPC.LO_LO + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.AR: + return PPC.WC_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.WC: + return PPC.AR_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.AR: + return PPC.HI_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.HI: + return PPC.AR_HI + + elif self.src_port_class == PC.WC and self.dst_port_class == PC.EM: + return PPC.WC_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.WC: + return PPC.EM_WC + + elif self.src_port_class == PC.HI and self.dst_port_class == PC.EM: + return PPC.HI_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.HI: + return PPC.EM_HI + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.AR: + return PPC.LO_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.LO: + return PPC.AR_LO + + elif self.src_port_class == PC.LO and self.dst_port_class == PC.EM: + return PPC.LO_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.LO: + return PPC.EM_LO + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.AR: + return PPC.AR_AR + + elif self.src_port_class == PC.AR and self.dst_port_class == PC.EM: + return PPC.AR_EM + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.AR: + return PPC.EM_AR + + elif self.src_port_class == PC.EM and self.dst_port_class == PC.EM: + return PPC.EM_EM + + def set_protocol_number(self, protocol): + """ + Function takes network protocol abbreviation as parameter and sets instance variable protocol_number as + enum value of that protocol. + + :param protocol: Network protocol abbreviation. + """ + if protocol == 'any': + self.protocol = Protocol.ANY + + elif protocol == 'tcp': + self.protocol = Protocol.TCP + + elif protocol == 'udp': + self.protocol = Protocol.UDP + + elif protocol == 'icmp': + self.protocol = Protocol.ICMP + + elif protocol == 'igmp': + self.protocol = Protocol.IGMP + + elif protocol == 'ggp': + self.protocol = Protocol.GGP + + elif protocol == 'st': + self.protocol = Protocol.ST + + elif protocol == 'egp': + self.protocol = Protocol.EGP + + elif protocol == 'gre': + self.protocol = Protocol.GRE + + elif protocol == 'esp': + self.protocol = Protocol.ESP + + elif protocol == 'ah': + self.protocol = Protocol.AH + + elif protocol == 'eigrp': + self.protocol = Protocol.EIGRP + + elif protocol == 'ospfigp': + self.protocol = Protocol.OSPFIGP + + def set_port(self, port, location): + """ + Function takes port value as parameter and sets instance variables source or destination port and port_class + with parameter value and port class of parameter. + + :param port: Port or port range value. + + :param location: Location of port or port range value (source/destination). + """ + if location == FilterRulePartLocation.SOURCE: + if port == 'any': + self.src_port_class = PC.WC + elif port == '0:1023': + self.src_port = port + self.src_port_class = PC.LO + elif port == '1024:65535': + self.src_port = port + self.src_port_class = PC.HI + elif len(port.split(':')) == 2: + self.src_port = port + self.src_port_class = PC.AR + else: + self.src_port = port + ':' + port + self.src_port_class = PC.EM + + elif location == FilterRulePartLocation.DESTINATION: + if port == 'any': + self.dst_port_class = PC.WC + elif port == '0:1023': + self.dst_port = port + self.dst_port_class = PC.LO + elif port == '1024:65535': + self.dst_port = port + self.dst_port_class = PC.HI + elif len(port.split(':')) == 2: + self.dst_port = port + self.dst_port_class = PC.AR + else: + self.dst_port = port + ':' + port + self.dst_port_class = PC.EM + + def set_ip_add(self, ip_address, location, is_ipv6): + """ + Function takes parameter ip address and sets instance variable source or destination ip_add_bin + as binary form of that ip address. It also sets instance variable source or destination ip_add_prefix_length + with ip address prefix length. + + :param ip_address: Ip address with prefix length. + + :param location: Location of ip address (source/destination). + + :param is_ipv6: True, if it is IPv6 address. + """ + if location == FilterRulePartLocation.SOURCE: + if ip_address == 'any': + self.src_ip_add_bin = '*' + self.src_ip_add_prefix_length = 0 + else: + ip_address = ip_address.split('/') + prefix_length = int(ip_address[1]) + self.src_ip_add_prefix_length = prefix_length + + if not is_ipv6: + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + else: + bin_ip_address = bin(int(ipaddress.IPv6Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(128) + + binary_ip_address_cut = bin_ip_address[:prefix_length] + self.src_ip_add_bin = binary_ip_address_cut + + elif location == FilterRulePartLocation.DESTINATION: + if ip_address == 'any': + self.dst_ip_add_bin = '*' + self.dst_ip_add_prefix_length = 0 + else: + ip_address = ip_address.split('/') + prefix_length = int(ip_address[1]) + self.dst_ip_add_prefix_length = prefix_length + + if not is_ipv6: + bin_ip_address = bin(int(ipaddress.IPv4Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(32) + else: + bin_ip_address = bin(int(ipaddress.IPv6Address(ip_address[0]))) + bin_ip_address = bin_ip_address[2:].zfill(128) + + binary_ip_address_cut = bin_ip_address[:prefix_length] + self.dst_ip_add_bin = binary_ip_address_cut diff --git a/lib/tuples_analyzer/processing_rules/filter_rule_generator.py b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py new file mode 100644 index 0000000..3bc3196 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/filter_rule_generator.py @@ -0,0 +1,460 @@ +#!/usr/bin/env python +"""Module containing definition of class FilterRuleGenerator.""" + +from ..processing_errors.enums.Error import Error +from ..processing_errors.error_process import ErrorProcess +from .enums.filter_rule_part_location import FilterRulePartLocation +from .enums.filter_rule_part_processing_result import FilterRulePartProcessingResult +from .enums.filter_rule_part_type import FilterRulePartType +from .filter_rule import FilterRule +from .supported_values import * +import ipaddress + + +class FilterRuleGenerator: + """ + Class containing only static functions for creating generator of FilterRule instances from filter set file and + specified rule format. + """ + + @staticmethod + def create_generator(lines_generator, rule_format, is_stderr_on): + """ + Function creates FilterRule class instances generator from all filter rules in filter set file. + Format of rules is needed for processing rules into instances. + + :param lines_generator: Generator of lines from file with filter rules. + + :param rule_format: String with rule format. + + :param is_stderr_on: If variable is true, printing error logs to stderr during parsing is enabled. + + :return: Generator of FilterRule instances. + """ + format_words = FilterRuleGenerator.split_line(rule_format) + format_length = len(format_words) + mandatory_words_count = FilterRuleGenerator.how_many_mandatory(format_words) + successful_yields = 0 + + # going through all lines + for line in lines_generator: + + # empty line check + if not line: + continue + + rule_parts = FilterRuleGenerator.split_line(line) + filter_rule = FilterRule() + + format_position = 0 + mandatory_processed = 0 + successful_assigment = 0 + + missing_mandatory = False + standalone_question_mark = False + + # going through all parts of line + for part in rule_parts: + + if part == '?': + standalone_question_mark = True + break + + # going through format parameters and keywords + while format_position != format_length: + + expected_part_type = format_words[format_position] + result = FilterRuleGenerator.part_processing(expected_part_type, part, filter_rule, format_words) + + if result == FilterRulePartProcessingResult.MANDATORY_PART_PROCESSED: + mandatory_processed += 1 + + if expected_part_type in format_parameters: + successful_assigment += 1 + + format_position += 1 + break + + elif result == FilterRulePartProcessingResult.MANDATORY_PART_MISSING: + missing_mandatory = True + break + + elif result == FilterRulePartProcessingResult.OPTIONAL_PART_PROCESSED: + + if expected_part_type[:-1] in format_parameters: + successful_assigment += 1 + + format_position += 1 + break + + elif result == FilterRulePartProcessingResult.OPTIONAL_PART_MISSING: + format_position += 1 + + # if condition is true, stop iterating through parts of filter rule + if format_position == format_length or missing_mandatory: + break + + # processing errors or yielding instance of FilterRule class + if (missing_mandatory or mandatory_processed != mandatory_words_count or successful_assigment == 0 + or standalone_question_mark) and not is_stderr_on: + pass + + elif missing_mandatory: + ErrorProcess.print_warning(f'Mandatory part: \'{expected_part_type}\' was expected ' + f'instead of: \'{str(FilterRuleGenerator.get_type(part, format_words).name)}' + f': {part}\', following rule is ignored: \'{line}\'.') + + elif mandatory_processed != mandatory_words_count: + ErrorProcess.print_warning(f'Not all mandatory parts of rule have been processed, ' + f'following rule is ignored: \'{line}\'.') + + elif successful_assigment == 0: + ErrorProcess.print_warning(f'Rule has not valuable content, ' + f'following rule is ignored: \'{line}\'.') + + elif standalone_question_mark: + ErrorProcess.print_warning(f'Character \'?\' can not be standalone part of rule, ' + f'following rule is ignored: \'{line}\'.') + + else: + successful_yields += 1 + yield filter_rule + + if successful_yields == 0: + ErrorProcess.process_error(Error.NO_VALUE_FILTER_SET_ERROR) + + @staticmethod + def part_processing(expected_part_type, part, filter_rule, format_words): + """ + If expected part (from format) matches with real part (from filter rule line), function sets one of attributes + in FilterRule instance to value of part and returns enum telling that mandatory or optional part was + processed. If mandatory or optional part is missing, function returns corresponding enum. + + :param expected_part_type: Parameter or keyword from rule format file. + + :param part: Part from filter rule line. + + :param filter_rule: Instance of FilterRule class. + + :param format_words: List with all format words. + + :return: Result type of processing filter rule part. + """ + part_type = FilterRuleGenerator.get_type(part, format_words) + + if part_type == FilterRulePartType.ANY: + part = "any" + + if part_type == FilterRulePartType.IPV4_ADDRESS: + part += '/32' + + if part_type == FilterRulePartType.IPV6_ADDRESS: + part += '/128' + + if ((expected_part_type == "PROTOCOL" or expected_part_type == "PROTOCOL?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PROTOCOL)): + + filter_rule.set_protocol_number(part) + + elif ((expected_part_type == "PROTOCOL" or expected_part_type == "PROTOCOL?") and + (part.isdigit() and int(part) in [e.value for e in Protocol])): + + filter_rule.set_protocol_number(Protocol(int(part)).name.lower()) + + elif ((expected_part_type == "SRC_PORT" or expected_part_type == "SRC_PORT?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PORT or + part_type == FilterRulePartType.PORT_RANGE)): + + filter_rule.set_port(part, FilterRulePartLocation.SOURCE) + + elif ((expected_part_type == "DST_PORT" or expected_part_type == "DST_PORT?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.PORT or + part_type == FilterRulePartType.PORT_RANGE)): + + filter_rule.set_port(part, FilterRulePartLocation.DESTINATION) + + elif ((expected_part_type == "SRC_IP" or expected_part_type == "SRC_IP?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IPV4_ADDRESS_MASK + or part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + or part_type == FilterRulePartType.IPV4_ADDRESS)): + + is_ipv6 = part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + filter_rule.set_ip_add(part, FilterRulePartLocation.SOURCE, is_ipv6) + + elif ((expected_part_type == "DST_IP" or expected_part_type == "DST_IP?") and + (part_type == FilterRulePartType.ANY or part_type == FilterRulePartType.IPV4_ADDRESS_MASK + or part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + or part_type == FilterRulePartType.IPV4_ADDRESS)): + + is_ipv6 = part_type == FilterRulePartType.IPV6_ADDRESS or part_type == FilterRulePartType.IPV6_ADDRESS_MASK + filter_rule.set_ip_add(part, FilterRulePartLocation.DESTINATION, is_ipv6) + + elif ((expected_part_type == "NUMBER" or expected_part_type == "NUMBER?") and + (part_type == FilterRulePartType.NUMBER or part_type == FilterRulePartType.PORT)): + pass + + elif ((expected_part_type == "WILDCARD" or expected_part_type == "WILDCARD?") and + (part_type == FilterRulePartType.WORD)): + pass + + elif ((expected_part_type == part or expected_part_type == part + '?') and + part_type == FilterRulePartType.KEYWORD): + pass + + elif FilterRuleGenerator.is_word_mandatory(expected_part_type): + return FilterRulePartProcessingResult.MANDATORY_PART_MISSING + + else: + return FilterRulePartProcessingResult.OPTIONAL_PART_MISSING + + if FilterRuleGenerator.is_word_mandatory(expected_part_type): + return FilterRulePartProcessingResult.MANDATORY_PART_PROCESSED + + else: + return FilterRulePartProcessingResult.OPTIONAL_PART_PROCESSED + + @staticmethod + def how_many_mandatory(rule_format): + """ + Function counts how many words are mandatory in rule format definition. + + :param rule_format: String with rule format. + + :return: Count of mandatory words in format. + """ + count = 0 + for part in rule_format: + if FilterRuleGenerator.is_word_mandatory(part): + count = count + 1 + return count + + @staticmethod + def is_word_mandatory(word): + """ + Every parameter or keyword in format is holding information, if part in filter rule is mandatory or optional. + Part is optional, if its definition in format ends with character '?', otherwise part is mandatory. + + :param word: Parameter or keyword from format. + + :return: Function returns true, if parameter word ends with '?'. + """ + string_length = len(word) + + if word[string_length - 1] != '?': + return True + else: + return False + + @staticmethod + def get_type(part, format_words): + """ + Function determines type of part of filter rule. Decision is made by acceptable format of part. + E.g. function knows it is a port, if part of rule is number between 0-65535. + + :param part: String with filter rule part. + + :param format_words: List with all format words. + + :return: Type of filter rule part. + """ + if FilterRuleGenerator.is_wildcard(part): + return FilterRulePartType.ANY + + elif FilterRuleGenerator.is_protocol(part): + return FilterRulePartType.PROTOCOL + + elif FilterRuleGenerator.is_ipv4_address(part): + return FilterRulePartType.IPV4_ADDRESS + + elif FilterRuleGenerator.is_ipv4_address_with_mask(part): + return FilterRulePartType.IPV4_ADDRESS_MASK + + elif FilterRuleGenerator.is_ipv6_address(part): + return FilterRulePartType.IPV6_ADDRESS + + elif FilterRuleGenerator.is_ipv6_address_with_mask(part): + return FilterRulePartType.IPV6_ADDRESS_MASK + + elif FilterRuleGenerator.is_port(part): + return FilterRulePartType.PORT + + elif part.isdigit(): + return FilterRulePartType.NUMBER + + elif FilterRuleGenerator.is_port_range(part): + return FilterRulePartType.PORT_RANGE + + elif FilterRuleGenerator.is_keyword(part, format_words): + return FilterRulePartType.KEYWORD + + else: + return FilterRulePartType.WORD + + @staticmethod + def is_wildcard(value): + """ + Function returns true, if parameter value is wildcard. + + :param value: String with possible wildcard. + + :return: True, if parameter is representation of wildcard, otherwise false. + """ + + if not isinstance(value, str): + return False + + value = value.lower() + + if value in supported_wildcard_list: + return True + else: + return False + + @staticmethod + def is_protocol(protocol): + """ + Function returns true, if parameter is network protocol abbreviation (TCP, UDP, ip, ...). + + :param protocol: String with possible network protocol abbreviation. + + :return: True, if parameter is network protocol abbreviation, otherwise false. + """ + if not isinstance(protocol, str): + return False + + case_insensitive_protocol = protocol.lower() + + if case_insensitive_protocol in supported_protocols: + return True + else: + return False + + @staticmethod + def is_port(port): + """ + Function finds out, if parameter is port (number between 0-65535). + + :param port: String with possible port. + + :return: Function returns true, if parameter of function is port. + """ + if port.isdigit() and 0 <= int(port) < 65536: + return True + else: + return False + + @staticmethod + def is_port_range(port_range): + """ + Function finds out, if parameter is port range (two ports with ':'as delimiter). + + :param port_range: String with possible port range. + + :return: Function returns true, if parameter of function is port range. + """ + port_range = port_range.split(':') + + if (len(port_range) == 2 and + FilterRuleGenerator.is_port(port_range[0]) and + FilterRuleGenerator.is_port(port_range[1]) and + int(port_range[0]) < int(port_range[1])): + return True + else: + return False + + @staticmethod + def is_keyword(keyword, format_words): + """ + Function finds out, if parameter keyword is part of rule format definition. + + :param keyword: String with possible keyword. + + :param format_words: List with all format words. + + :return: True, if parameter of function is keyword in format. + """ + if keyword in format_words or keyword + '?' in format_words: + return True + else: + return False + + @staticmethod + def is_ipv4_address(ip_address): + """ + Function returns true, if parameter of function is IPv4 address in decimal form without mask (prefix length). + + :param ip_address: String with possible IPv4 address in decimal form. + + :return: True, if parameter of function is IPv4 address. + """ + try: + ipaddress.IPv4Address(ip_address) + except ipaddress.AddressValueError: + return False + + return True + + @staticmethod + def is_ipv4_address_with_mask(ip_address): + """ + Function returns true, if parameter of function is IPv4 address in decimal form with mask (prefix length). + + :param ip_address: String with possible IPv4 address with mask in decimal form. + + :return: True, if parameter of function is IPv4 address with mask. + """ + possible_address = ip_address.split('/') + + if len(possible_address) != 2 or not possible_address[1].isdigit() or int(possible_address[1]) < 0 or int( + possible_address[1]) > 32 or not FilterRuleGenerator.is_ipv4_address(possible_address[0]): + return False + + return True + + + @staticmethod + def is_ipv6_address(ip_address): + """ + Function returns true, if parameter of function is IPv6 address without mask (prefix length). + + :param ip_address: String with possible IPv6 address. + + :return: True, if parameter of function is IPv6 address. + """ + try: + ipaddress.IPv6Address(ip_address) + except ipaddress.AddressValueError: + return False + + return True + + @staticmethod + def is_ipv6_address_with_mask(ip_address): + """ + Function returns true, if parameter of function is IPv6 address with mask (prefix length). + + :param ip_address: String with possible IPv6 address with mask. + + :return: True, if parameter of function is IPv6 address with mask. + """ + possible_address = ip_address.split('/') + + if len(possible_address) != 2 or not possible_address[1].isdigit() or int(possible_address[1]) < 0 or int( + possible_address[1]) > 128 or not FilterRuleGenerator.is_ipv6_address(possible_address[0]): + return False + + return True + + @staticmethod + def split_line(line): + """ + Function firstly replaces line characters ',' and '=' with empty space. Then split the line by whitespace + into parts and returns list with splitted parts from line. + + :param line: String which will be splitted to parts. + + :return: List with splitted parts by whitespace from line. + """ + line = line.replace("=", " ") + line = line.replace(",", " ") + return line.split() diff --git a/lib/tuples_analyzer/processing_rules/supported_values.py b/lib/tuples_analyzer/processing_rules/supported_values.py new file mode 100644 index 0000000..b49fc12 --- /dev/null +++ b/lib/tuples_analyzer/processing_rules/supported_values.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +"""Module containing global lists of supported protocols, wildcard representations and valuable format parameters.""" +from .enums.protocol_numbers import Protocol + +supported_protocols = [str(e.name).lower() for e in Protocol] +format_parameters = ["PROTOCOL", "SRC_IP", "SRC_PORT", "DST_IP", "DST_PORT"] +supported_wildcard_list = ["any", "all", "*", "ip", "0"] + diff --git a/lib/tuples_analyzer/value_formats/__init__.py b/lib/tuples_analyzer/value_formats/__init__.py new file mode 100644 index 0000000..aa33cb3 --- /dev/null +++ b/lib/tuples_analyzer/value_formats/__init__.py @@ -0,0 +1 @@ +"""Package with classes for formatting different types of values to specified form.""" diff --git a/lib/tuples_analyzer/value_formats/value_format.py b/lib/tuples_analyzer/value_formats/value_format.py new file mode 100644 index 0000000..ef636f0 --- /dev/null +++ b/lib/tuples_analyzer/value_formats/value_format.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"""Module containing definition of class Format.""" + + +class Format: + """ + Class contains functions for formatting different types of values to specified form. + """ + + @staticmethod + def decimal(decimal_value): + """ + Function formats decimal value to form with 8 decimal numbers. + + :param decimal_value: Decimal value. + + :return: Decimal value with 8 decimal numbers. + """ + return format(decimal_value, '.8f') diff --git a/patches/improvements.patch b/patches/improvements.patch new file mode 100644 index 0000000..2323a82 --- /dev/null +++ b/patches/improvements.patch @@ -0,0 +1,9463 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } +diff --git a/FilterList.cc b/FilterList.cc +index c123529..2467dfd 100644 +--- a/FilterList.cc ++++ b/FilterList.cc +@@ -17,9 +17,12 @@ FilterList::FilterList() { + num = 0; + } + +-FilterList::~FilterList() { ++FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -41,7 +44,7 @@ void FilterList::clear() { + struct FilterList_item* FilterList::operator()(int i) { + if (i <= 0 || (i > num && num > 0)) { + fprintf(stderr,"FilterList::operator(): item %d out of range, num = %d\n",i,num); +- exit(1); ++ exit(1); + } + // Items are maintained in-order + // Index i items to the "right" +@@ -57,7 +60,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +75,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +113,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -121,14 +124,14 @@ void FilterList::push(struct filter filt) { + first = temp; + num++; + return; +-} ++} + + // Print the contents of the FilterList. + void FilterList::print(FILE* fp) { + int addr[4]; + unsigned temp; + struct FilterList_item *tempfilt; +- ++ + for (tempfilt = first; tempfilt != NULL; tempfilt = tempfilt->next){ + // Print new filter character + fprintf(fp,"@"); +@@ -143,7 +146,7 @@ void FilterList::print(FILE* fp) { + fprintf(fp, "%d.%d.%d.%d/%d\t", + addr[0], addr[1], addr[2], addr[3], + tempfilt->filt.sa_len); +- // Print destination address ++ // Print destination address + addr[0] = addr[1] = addr[2] = addr[3] = 0; + temp = 0; + temp = tempfilt->filt.da; +@@ -154,13 +157,13 @@ void FilterList::print(FILE* fp) { + fprintf(fp, "%d.%d.%d.%d/%d\t", + addr[0], addr[1], addr[2], addr[3], + tempfilt->filt.da_len); +- // Print source port ++ // Print source port + fprintf(fp, "%d : %d\t", + tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +- // Print destination port ++ // Print destination port + fprintf(fp, "%d : %d\t", + tempfilt->filt.dp[0], tempfilt->filt.dp[1]); +- // Print protocol ++ // Print protocol + if (tempfilt->filt.prot_num == 0) fprintf(fp, "0x00/0x00\t"); + else fprintf(fp, "0x%02x/0xFF\t", tempfilt->filt.prot_num); + // Print flags +@@ -170,8 +173,8 @@ void FilterList::print(FILE* fp) { + for (int j = 0; j < tempfilt->filt.num_ext_field; j++){ + fprintf(fp, "%d\t", + tempfilt->filt.ext_field[j]); +- } +- // Print newline ++ } ++ // Print newline + fprintf(fp,"\n"); + } + } +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; +diff --git a/PrefixList.cc b/PrefixList.cc +index a3df1dc..58f75e1 100644 +--- a/PrefixList.cc ++++ b/PrefixList.cc +@@ -24,8 +24,8 @@ PrefixList::PrefixList() { + } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { +diff --git a/README b/README +index 116aac2..f104e85 100644 +--- a/README ++++ b/README +@@ -75,17 +75,17 @@ PPC + 10 AR/WC source port arbitrary range, destination port wildcard + 11 HI/AR source port [1024:65535], destination port arbitrary range + 12 AR/HI source port arbitrary range, destination port [1024:65535] +-13 LO/AR source port [0:1023], destination port arbitrary range +-14 AR/LO source port arbitrary range, destination port [0:1023] +-15 AR/AR source port arbitrary range, destination port arbitrary range +-16 WC/EM source port wildcard, destination port exact match +-17 EM/WC source port exact match, destination port wildcard +-18 HI/EM source port [1024:65535], destination port exact match +-19 EM/HI source port exact match, destination port [1024:65535] +-20 LO/EM source port [0:1023], destination port exact match +-21 EM/LO source port exact match, destination port [0:1023] ++13 WC/EM source port wildcard, destination port exact match ++14 EM/WC source port exact match, destination port wildcard ++15 HI/EM source port [1024:65535], destination port exact match ++16 EM/HI source port exact match, destination port [1024:65535] ++17 LO/AR source port [0:1023], destination port arbitrary range ++18 AR/LO source port arbitraty range, destination port [0:1023] ++19 LO/EM source port [0:1023], destination port exact match ++20 EM/LO source port exact match, destination port [0:1023] ++21 AR/AR source port arbitraty range, destination port arbitrary range + 22 AR/EM source port arbitrary range, destination port exact match +-23 EM/AR source port exact match, destination port exact match arbitrary range ++23 EM/AR source port exact match, destination port arbitrary range + 24 EM/EM source port exact match, destination port exact match + + -flags +diff --git a/TupleBST.cc b/TupleBST.cc +index 9163d9b..da91dcc 100644 +--- a/TupleBST.cc ++++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ +diff --git a/custom_db.cc b/custom_db.cc +index 6f8d193..3ec8a52 100644 +--- a/custom_db.cc ++++ b/custom_db.cc +@@ -20,15 +20,58 @@ + #include "redundant_filter_check.h" + #include "TupleBST.h" + #include "custom_db.h" ++#include "ip_prefix.h" ++#include "trie.h" ++#include "filter_graph.h" ++ ++ ++/* ++ * Transforms a pruned source/destination trie into a set of edges from/to the ++ * 's'/'t' node in the filter graph. ++ * The given trie is recursively traversed. When the traversed node is a prefix ++ * node, adding of the corresponding edge from/to the 's'/'t' node of the ++ * filter graph is triggered. Weight of the added edge is set according to the ++ * number of prefixes represented by the current prefix node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A pointer to the current trie node. ++ * @param src_trie The trie node referenced by parameter node belongs to ++ * the source trie (TRUE) or the destination trie (FALSE). ++ * @param prefix_str The prefix represented by the current node encoded as a ++ * string of bit values. ++ * @param graph A pointer to the filter graph object. ++ */ ++void trie_to_graph(const trie_node* node, bool src_trie, string prefix_str, Filter_graph* graph) { ++ if (node != NULL) { // non-empty subtree ++ int prefix_count = node->prefixes; ++ if (prefix_count > 0) { // prefix node ++ // add current prefix to the filter graph, either as "s_prefix" or as "t_prefix" ++ IP_prefix prefix(prefix_str, true); ++ if (src_trie) { ++ graph->add_s_prefix(prefix, prefix_count); ++ } else { ++ graph->add_t_prefix(prefix, prefix_count); ++ } ++ } ++ // call this function on both zero and one subtrees ++ trie_to_graph(node->zero, src_trie, prefix_str + "0", graph); ++ trie_to_graph(node->one, src_trie, prefix_str + "1", graph); ++ } else { // empty subtree ++ return; ++ } ++} // end trie_to_graph() + + + int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ + ++ // generate 100 times more filters (because of successive trie pruning) ++ int temp_num_filters = num_filters * 100; ++ + printf("Initializing data structures...\n"); + // Read in scale + int scale = read_scale(fp_in); + // printf("scale = %d\n",scale); +- float scale_factor = (float)num_filters/(float)scale; ++ float scale_factor = (float)temp_num_filters/(float)scale; + // printf("scale_factor = %.4f\n",scale); + + // Read protocol parameters, initialize data structure +@@ -80,7 +123,10 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + // Temporary filter + // struct filter temp_filter; +- struct filter *temp_filters = new struct filter[num_filters+1]; ++ struct filter *temp_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -89,7 +135,7 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf("Creating application specifications...\n"); + + // For all filters: +- for (int i = 1; i <= num_filters; i++){ ++ for (int i = 1; i <= temp_num_filters; i++){ + // Select a protocol via random number + p = drand48(); + temp_filters[i].prot_num = protL->choose_prot((float)p); +@@ -143,6 +189,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -180,10 +228,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + } + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); + (*Stree).build_tree(Flist,temp_filters); +- delete(Stree); + /* + printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- for (int i = 1; i <= num_filters; i++) ++ for (int i = 1; i <= temp_num_filters; i++) + printf("filter[%d].sa = %u/%d\n",i,temp_filters[i].sa,temp_filters[i].sa_len); + */ + printf(" \tdone\n"); +@@ -203,13 +250,245 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + (*Dtree).build_tree(Flist,temp_filters); + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- delete(Dtree); + printf(" \tdone\n"); + + delete(Flist); + ++ ++// **************************************************************************** ++// START of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ // transform filter set into filter graph and insert source/destination ++ // prefixes of filters into corresponding tries ++ Filter_graph graph; ++ Trie src_trie; ++ Trie dst_trie; ++ for (int i = 1; i <= temp_num_filters; i++) { ++ graph.add_filter(&(temp_filters[i])); ++ src_trie.insert(IP_prefix(temp_filters[i].sa, temp_filters[i].sa_len)); ++ dst_trie.insert(IP_prefix(temp_filters[i].da, temp_filters[i].da_len)); ++ } ++ ++ // get statistics of source and destination tries ++ trie_stats src_trie_stats, dst_trie_stats; ++ src_trie.get_stats(src_trie_stats); ++ dst_trie.get_stats(dst_trie_stats); ++ ++ // initialize data structures for trie-related distributions ++ vector src_prefixes(129,0); ++ vector src_one_child(129,0); ++ vector src_two_children(129,0); ++ vector src_skew(129,0); ++ vector dst_prefixes(129,0); ++ vector dst_one_child(129,0); ++ vector dst_two_children(129,0); ++ vector dst_skew(129,0); ++ ++ // get source and destination prefix length distributions ++ // Use prefix length distributions from already generated source and ++ // destination prefix sets as ClassBench-generated rule sets follow them ++ // quite precisely. ++ for (int i = 0; i < 129; i++) { ++ src_prefixes[i] = (float)src_trie_stats.classbench.prefix_lengths[i] / ++ (float)src_trie_stats.classbench.prefixes; ++ dst_prefixes[i] = (float)dst_trie_stats.classbench.prefix_lengths[i] / ++ (float)dst_trie_stats.classbench.prefixes; ++ } ++ ++ // get other src distributions ++ // Copy the values that were already read from the parameter file into Stree. ++ for (int i = 0; i <= 32; i++) { ++ src_one_child[i] = Stree->get_p1child()[i]; ++ src_two_children[i] = Stree->get_p2child()[i]; ++ src_skew[i] = Stree->get_skew()[i]; ++ } ++ delete(Stree); ++ ++ // get other dst distributions ++ // Copy the values that were already read from the parameter file into Dtree. ++ for (int i = 0; i <= 32; i++) { ++ dst_one_child[i] = Dtree->get_p1child()[i]; ++ dst_two_children[i] = Dtree->get_p2child()[i]; ++ dst_skew[i] = Dtree->get_skew()[i]; ++ } ++ delete(Dtree); ++ ++ // prune source and destination tries to 1/100 of the original prefix sets ++ src_trie.prune(num_filters, src_prefixes, src_one_child, ++ src_two_children, src_skew); ++ dst_trie.prune(num_filters, dst_prefixes, dst_one_child, ++ dst_two_children, dst_skew); ++ ++ // extend filter graph according to pruned tries ++ trie_to_graph(src_trie.get_root(), true, "", &graph); ++ trie_to_graph(dst_trie.get_root(), false, "", &graph); ++ ++ // modify the filter graph to conform with the flow network specification ++ graph.to_flow_network(); ++ ++ // compute maximum flow for the current flow network ++ int max_flow = graph.max_flow(); ++ ++ // auxiliary variables for construction of the set of pruned filters ++ struct filter* pruned_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ pruned_filters[i].num_ext_field = 0; ++ } ++ int pruned_filters_i = 1; ++ ++ /* ++ * 1st phase of construction of the set of pruned filters ++ */ ++ // iterate over all filters ++ const node_list_item* node; ++ node = graph.get_src_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ filter_list_item* filter = neighbour->filters; ++ for (int i = 0; i < neighbour->flow; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ // copy filters from the maximum flow to the pruned_filters array ++ copy_filter(pruned_filters[pruned_filters_i], *(filter->filter)); ++ pruned_filters_i++; ++ filter = filter->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ neighbour = neighbour->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ node = node->next; ++ } ++ ++ /* ++ * 2nd phase of construction of the set of pruned filters ++ */ ++ // auxiliary variables for looking for not fully utilized source prefixes ++ neighbour_list_item* s_neighbour = (graph.get_s_node() != NULL) ? ++ graph.get_s_node()->neighbours : NULL; ++ // iterate over all destination prefixes ++ node = graph.get_dst_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ if (neighbour != NULL) { ++ int free_weight = neighbour->weight - neighbour->flow; ++ // auxiliary variables for looking for not fully utilized filters with ++ // current destination prefix ++ const node_list_item* src_node = graph.get_src_nodes(); ++ neighbour_list_item* src_neighbour; ++ filter_list_item* src_filter; ++ int src_filter_index = 0; ++ // for each not fully utilized destination prefix ++ for (int i = 0; i < free_weight; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ ++// FILTERS start -------------------------------------------------------------- ++ ++ // iterate over all filters with current destination prefix ++ while (src_node != NULL) { ++ src_neighbour = src_node->neighbours; ++ while (src_neighbour != NULL) { ++ if (src_neighbour->node->prefix == node->prefix) { ++ src_filter = src_neighbour->filters; ++ // skip over all filters from the maximum flow ++ for (; ++ src_filter_index < src_neighbour->flow; ++ src_filter_index++) { ++ src_filter = src_filter->next; ++ } ++ if (src_filter != NULL) {// this filter is not fully ++ // utilized ++ ++// SOURCE PREFIXES start ------------------------------------------------------ ++ ++ // find the first not fully utilized source prefix ++ while (s_neighbour != NULL) { ++ // if this source prefix is not fully utilized ++ if (s_neighbour->flow < s_neighbour->weight) { ++ // create local copy of the selected filter and ++ // modify its source prefix ++ struct filter pruned_filter; ++ copy_filter(pruned_filter, *(src_filter->filter)); ++ pruned_filter.sa = ++ s_neighbour->node->prefix.get_prefix_unsigned(); ++ pruned_filter.sa_len = ++ s_neighbour->node->prefix.get_length(); ++ // inset the filter into the pruned_filters array ++ pruned_filters[pruned_filters_i++] = ++ pruned_filter; ++ // increment flow value through used edges ++ s_neighbour->flow++; ++ src_neighbour->flow++; ++ neighbour->flow++; ++ // terminate looking for the next not fully ++ // utilized source prefix ++ break; ++ } ++ s_neighbour = s_neighbour->next; ++ } ++ // always terminate looking for not fully utilized ++ // filters because of the following reasons: ++ // * if not fully utilized source prefix was found, ++ // move to the next not fully utilized destination ++ // prefix ++ // * if not fully utilized source prefix was not ++ // found, terminate inserting filters into the ++ // pruned_filters array at all ++ break; ++ ++// SOURCE PREFIES end --------------------------------------------------------- ++ ++ } else { // this filter is fully utilized ++ src_filter_index = 0; ++ } ++ } ++ src_neighbour = src_neighbour->next; ++ } ++ // if the previous cycle was broken, break also this cycle ++ // (because of the same reasons) ++ if (src_neighbour != NULL) { ++ break; ++ } ++ src_node = src_node->next; ++ } ++ // if either all filters or prefixes are fully utilized, terminate ++ // looking for not fully utilized filters ++ if ((src_node == NULL) || (s_neighbour == NULL)) { ++ break; ++ } ++ ++// FILTERS end ---------------------------------------------------------------- ++ ++ } ++ } ++ // if all source prefixes are fully utilized or enough filters have been ++ // selected, terminate looking for not fully utilized destination prefixes ++ if ((s_neighbour == NULL) || (pruned_filters_i == num_filters+1)) { ++ break; ++ } ++ node = node->next; ++ } ++ ++// **************************************************************************** ++// END of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ + printf("Removing redundant filters and ordering nested filters...\n"); +- int filter_cnt = remove_redundant_filters(num_filters,filters,temp_filters); ++ int filter_cnt = remove_redundant_filters(pruned_filters_i-1,filters,pruned_filters); + printf(" \tdone\n"); + + // Resolve conflicts, throw away filters if necessary +@@ -219,7 +498,16 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ if (pruned_filters[i].num_ext_field > 0) { ++ delete[] (pruned_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); ++ delete[] (pruned_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +diff --git a/dbintree.cc b/dbintree.cc +index 9274710..bb45062 100644 +--- a/dbintree.cc ++++ b/dbintree.cc +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +diff --git a/dbintree.h b/dbintree.h +index 5509fc3..d189380 100644 +--- a/dbintree.h ++++ b/dbintree.h +@@ -51,4 +51,15 @@ class dbintree { + void print_corr(FILE*); // print correlation per level + void build_tree(dlist* Flist, struct filter filters[]); + void lsort(); // sort nodes by level ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; +diff --git a/filter_graph.cc b/filter_graph.cc +new file mode 100644 +index 0000000..726869a +--- /dev/null ++++ b/filter_graph.cc +@@ -0,0 +1,785 @@ ++// filter_graph.cc: Filter_graph class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "stdinc.h" ++#include "flow_network.h" ++#include "filter_graph.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Auxiliary (non-member) functions ************************************* ++ ++ ++/* ++ * Private function that builds a flow network corresponding to the filter ++ * graph. ++ * In three iterations the function traverses all edges of the filter graph ++ * (i.e., s_node->src_nodes, src_nodes->dst_nodes, and dst_nodes->t_node edges) ++ * and constructs the flow network corresponding to this graph. Each edge of ++ * the filter graph can be represented by at most two edges of the flow ++ * network -- a forward and backward edge. Note that they are included into the ++ * flow network only if their residual capacity is greater than zero. ++ * The function expects that the input graph is already a valid flow network, ++ * i.e., it contains only one node without input edges (the 's' node) and only ++ * one node without output edges (the 't' node). ++ * @param network Reference to the (most probably empty) flow network object. ++ * @param graph Pointer to the constant filter graph object. ++ */ ++void build_flow_network(Flow_network& network, const Filter_graph* graph) { ++ // declatarion of "phase" variables ++ const node_list_item* list; ++ int src_list; ++ int dst_list; ++ ++ // iteration through three phases ++ for (int i = 0; i < 3; i++) { ++ // setting of phase variables ++ switch (i) { ++ case 0: // edges from the 's' node to destination nodes ++ list = graph->get_s_node(); ++ src_list = 0; ++ dst_list = 1; ++ break; ++ case 1: // edges from source nodes to destination nodes ++ list = graph->get_src_nodes(); ++ src_list = 1; ++ dst_list = 2; ++ break; ++ case 2: // edges from destination nodes to the 'd' node ++ list = graph->get_dst_nodes(); ++ src_list = 2; ++ dst_list = 3; ++ break; ++ } ++ ++ // iteration over all nodes in the list ++ while (list != NULL) { ++ neighbour_list_item* neighbour = list->neighbours; ++ // iteration over all neighbours (i.e., edges of the filter graph) ++ while (neighbour != NULL) { ++ // compute residual capacity of forward and backward edges ++ int capacity_forward = neighbour->weight - neighbour->flow; ++ int capacity_backward = neighbour->flow; ++ // insert the forward edge, if it has capacity > 0 ++ if (capacity_forward > 0) { ++ network.add_edge(list->prefix, src_list, ++ neighbour->node->prefix, dst_list, ++ neighbour, true, capacity_forward); ++ } ++ // insert the backward edge, if it has capacity > 0 ++ if (capacity_backward > 0) { ++ network.add_edge(neighbour->node->prefix, dst_list, ++ list->prefix, src_list, ++ neighbour, false, capacity_backward); ++ } ++ // move to the next edge ++ neighbour = neighbour->next; ++ } ++ // move to the next node ++ list = list->next; ++ } ++ } ++} // end build_flow_network() ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++node_list_item* Filter_graph::copy_node_list(const node_list_item* orig) { ++ // initialize pointer to copied node list ++ node_list_item* result = (orig == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // node list level of copying ++ node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->pruned = orig->pruned; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // neighbour list level of copying ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->weight = orig_neighbours->weight; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->filters = (orig_neighbours->filters == NULL) ? ++ NULL : ++ new filter_list_item; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ ++ // filter list level of copying ++ filter_list_item* orig_filters = orig_neighbours->filters; ++ filter_list_item* copy_filters = copy_neighbours->filters; ++ while (orig_filters != NULL) { ++ // list item members initialization ++ copy_filters->filter = orig_filters->filter; ++ copy_filters->next = (orig_filters->next == NULL) ? ++ NULL : ++ new filter_list_item; ++ // move to the next item of filter list ++ copy_filters = copy_filters->next; ++ orig_filters = orig_filters->next; ++ } ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Filter_graph::remove_node_list(node_list_item** list) { ++ // traverse all nodes ++ while ((*list) != NULL) { ++ // get pointer to the first node ++ node_list_item* first_node = *list; ++ ++ // correctly deallocate its whole neighbour list ++ remove_neighbour_list(&(first_node->neighbours)); ++ ++ // move to the next node list item and deallocate the current one ++ node_list_item* next_node = first_node->next; ++ delete first_node; ++ *list = next_node; ++ } ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ */ ++void Filter_graph::remove_neighbour_list(neighbour_list_item** list) { ++ // traverse all neighbours ++ while ((*list) != NULL) { ++ // get pointer to the first neighbour ++ neighbour_list_item* first_neighbour = *list; ++ ++ // correctly deallocate it whole filter list ++ remove_filter_list(&(first_neighbour->filters)); ++ ++ // move to the next neighbour list item and deallocate the current one ++ neighbour_list_item* next_neighbour = first_neighbour->next; ++ delete first_neighbour; ++ *list = next_neighbour; ++ } ++} // end remove_neighbour_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole filter list. ++ */ ++void Filter_graph::remove_filter_list(filter_list_item** list) { ++ // traverse all filters ++ while ((*list) != NULL) { ++ // get pointer to the first filter ++ filter_list_item* first_filter = *list; ++ ++ // move to the next filter list item and deallocate the current one ++ filter_list_item* next_filter = first_filter->next; ++ delete first_filter; ++ *list = next_filter; ++ } ++} // end remove_filter_list() ++ ++ ++/* ++ * Private static function that sets correct values of neighbour node pointers, ++ * which cannot be correctly initialized during copying. ++ */ ++void Filter_graph::set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst) { ++ // traverse all nodes ++ while (orig != NULL) { ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* src_neighbours = src->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct neighbour node pointer ++ src_neighbours->node = find_node(orig_neighbours->node->prefix, dst); ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ src_neighbours = src_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ src = src->next; ++ } ++ ++ return; ++} // end set_neighbour_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++node_list_item* Filter_graph::find_node(const IP_prefix& prefix, ++ node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++neighbour_list_item* Filter_graph::find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ */ ++filter_list_item* Filter_graph::find_filter(const struct filter* filter, ++ filter_list_item* list) { ++ // traverse all filter nodes ++ while (list != NULL) { ++ if (list->filter == filter) { ++ // corresponding filter node - return pointer to it ++ return list; ++ } else { ++ // filter node pointing to different filter - move to the next item of ++ // filter list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding filter node was not found ++ return NULL; ++} // end find_filter() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Filter_graph::insert_node(const IP_prefix& prefix, ++ node_list_item** list) { ++ // allocate and initialize new prefix node ++ node_list_item* node = new node_list_item; ++ node->prefix = prefix; ++ node->pruned = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node corresponding to the ++ * given prefix node at the beginning of the given list of neighbour nodes. ++ */ ++void Filter_graph::insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ neighbour_list_item* node = new neighbour_list_item; ++ node->node = neighbour; ++ node->weight = 0; ++ node->flow = 0; ++ node->filters = NULL; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that inserts a filter node pointing to the given ++ * filter at the beginning of the given list of filter nodes. ++ */ ++void Filter_graph::insert_filter(const struct filter* filter, ++ filter_list_item** list) { ++ // allocate and initialize new filter node ++ filter_list_item* node = new filter_list_item; ++ node->filter = filter; ++ ++ // insert new filter node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_filter() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ */ ++void Filter_graph::print_node_list(const node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> " << neighbours->node->prefix.get_prefix() << "/" ++ << neighbours->node->prefix.get_length() << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->weight ++ << ")" << endl; ++ filter_list_item* filters = neighbours->filters; ++ while (filters != NULL) { ++ // print filter list items ++ cout << "| | +-> " << filters->filter->sp[0] << ":" ++ << filters->filter->sp[1] << " " ++ << filters->filter->dp[0] << ":" ++ << filters->filter->dp[1] << " " ++ << filters->filter->prot_num << endl; ++ // move to the next filter ++ filters = filters->next; ++ } ++ // moce tothe next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++/* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ */ ++void Filter_graph::remove_and_reset() { ++ for (int i = 0; i < 4; i++) { ++ // select the correct node list for iteration ++ node_list_item** node_ptr; ++ switch (i) { ++ case 0: ++ node_ptr = &s_node; ++ break; ++ case 1: ++ node_ptr = &src_nodes; ++ break; ++ case 2: ++ node_ptr = &dst_nodes; ++ break; ++ case 3: ++ node_ptr = &t_node; ++ break; ++ } ++ ++ // iterate over all nodes in the list ++ while ((*node_ptr) != NULL) { ++ node_list_item* node = *node_ptr; ++ if (node->pruned == false) { // remove the non-pruned node ++ (*node_ptr) = node->next; ++ delete node; ++ } else { // reset the "pruned" flag of the pruned node ++ node->pruned = false; ++ node_ptr = &(node->next); ++ } ++ } ++ } ++} // end remove_and_reset() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Filter_graph::Filter_graph() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Filter_graph() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Filter_graph::Filter_graph(const Filter_graph& orig) { ++ // acquire members of the original object ++ const node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const node_list_item* orig_s_node = orig.get_s_node(); ++ const node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(orig_t_node, t_node, NULL); ++ set_neighbour_nodes(orig_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(orig_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(orig_s_node, s_node, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Destructor. ++ */ ++Filter_graph::~Filter_graph() { ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++} // end ~Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Filter_graph& Filter_graph::operator=(const Filter_graph& copy) { ++ // destruct the original object ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++ ++ // acquire members of the copied object ++ const node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const node_list_item* copy_s_node = copy.get_s_node(); ++ const node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(copy_t_node, t_node, NULL); ++ set_neighbour_nodes(copy_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(copy_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(copy_s_node, s_node, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Modifies filter graph to add the specified filter into the set of filters ++ * represented by the graph. ++ */ ++void Filter_graph::add_filter(const struct filter* filter) { ++ // acquire source and destination prefixes ++ IP_prefix src_pref(filter->sa, filter->sa_len); ++ IP_prefix dst_pref(filter->da, filter->da_len); ++ ++ // find source prefix node and insert such node if it does not exist ++ node_list_item* src_node = find_node(src_pref, src_nodes); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_pref, &src_nodes); ++ src_node = src_nodes; ++ } ++ ++ // find destination prefix node and insert such node if it does not exist ++ node_list_item* dst_node = find_node(dst_pref, dst_nodes); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_pref, &dst_nodes); ++ dst_node = dst_nodes; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(dst_node, &(src_node->neighbours)); ++ neighbour = src_node->neighbours; ++ } ++ ++ // find filter node pointing to the specified filter and insert such node if ++ // it does not exist ++ filter_list_item* filter_node = find_filter(filter, neighbour->filters); ++ if (filter_node == NULL) { ++ insert_filter(filter, &(neighbour->filters)); ++ neighbour->weight += 1; ++ } ++} // end add_filter() ++ ++ ++/* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ */ ++void Filter_graph::add_s_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 's' node and allocate it if it does not exist ++ if (s_node == NULL) { ++ insert_node(IP_prefix(), &s_node); ++ s_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the source nodes list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* src_node = find_node(prefix, src_nodes); ++ ++ // find a neighbour node corresponding to the given prefix ++ neighbour_list_item* neighbour = find_neighbour(src_node, ++ s_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(src_node, &(s_node->neighbours)); ++ neighbour = s_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set source node's pruned flag to true ++ src_node->pruned = true; ++} // end add_s_prefix() ++ ++ ++/* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the given ++ * value. ++ */ ++void Filter_graph::add_t_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 't' node and allocate it if it does not exist ++ if (t_node == NULL) { ++ insert_node(IP_prefix(), &t_node); ++ t_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the destination nodes ++ // list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* dst_node = find_node(prefix, dst_nodes); ++ ++ // find a neighbour node corresponding to the 't' node ++ neighbour_list_item* neighbour = find_neighbour(t_node, ++ dst_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(t_node, &(dst_node->neighbours)); ++ neighbour = dst_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set destination node's pruned flag to true ++ dst_node->pruned = true; ++} // end add_t_prefix() ++ ++ ++/* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ */ ++void Filter_graph::to_flow_network() { ++ // 1) remove filters containing at least one non-pruned prefix ++ node_list_item* node = src_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all neighbours of this node ++ remove_neighbour_list(&(node->neighbours)); ++ } else { // remove only neighbours pointing to a non-pruned node ++ neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this neighbour ++ remove_filter_list(&(neighbour->filters)); ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } else { // just move to the next neighbour ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ } ++ node = node->next; ++ } ++ ++ // 2) remove non-pruned nodes and reset the "pruned" flag of other nodes ++ remove_and_reset(); ++ ++ // 3) BFS to set the "pruned" flag of visited nodes with at least one ++ // neighbour and the 's' and 't' nodes ++ queue q; ++ q.push(s_node); ++ // do the BFS ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ node_list_item* node = q.front(); ++ q.pop(); ++ // set the "pruned" flag if the list of neighbours is non-empty ++ if (node->neighbours != NULL) { ++ node->pruned = true; ++ } ++ // insert neighbours into the queue ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ q.push(neighbour->node); ++ neighbour = neighbour->next; ++ } ++ } ++ // set the "pruned" flag of the 's' and 't' nodes ++ s_node->pruned = true; ++ t_node->pruned = true; ++ ++ // 4) remove edges from the 's' node going to non-pruned nodes ++ neighbour_list_item** neighbour_ptr = &(s_node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this edge ++ // there are no filters represented by edges from the 's' node ++ (*neighbour_ptr) = neighbour->next; ++ delete neighbour; ++ } else { // move to the next edge ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ ++ // 5) remove edges to the 't' node going from non-pruned nodes ++ node = dst_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all edges going from this node ++ remove_neighbour_list(&(node->neighbours)); ++ } ++ // move to the next node ++ node = node->next; ++ } ++ ++ // 6) remove non-pruned nodes (and reset the "pruned" flag of other nodes) ++ remove_and_reset(); ++} // end to_flow_network() ++ ++ ++/* ++ * Computes maximum flow using Dinic's algorithm. ++ */ ++int Filter_graph::max_flow() { ++ int max_flow = 0; ++ int flow_inc; ++ ++ do { // iterate until the flow cannot be improved ++ // build flow network corresponding to the filter graph ++ Flow_network network; ++ build_flow_network(network, this); ++ ++ // transform the flow network into the level graph ++ network.to_level_graph(); ++ ++ // compute a blocking flow in the flow network and update the flow in the ++ // filter graph accordingly ++ flow_inc = network.find_blocking_flow(); ++ max_flow += flow_inc; ++ } while (flow_inc != 0); ++ ++ return max_flow; ++} // end max_flow() ++ ++ ++/* ++ * Prints the filter graph. ++ */ ++void Filter_graph::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/filter_graph.h b/filter_graph.h +new file mode 100644 +index 0000000..601f2cd +--- /dev/null ++++ b/filter_graph.h +@@ -0,0 +1,437 @@ ++// filter_graph.h: header file for Filter_graph class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FILTER_GRAPH_H ++#define FILTER_GRAPH_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct node_list_item node_list_item; ++typedef struct neighbour_list_item neighbour_list_item; ++typedef struct filter_list_item filter_list_item; ++ ++/* ++ * A structure representing an item in a list of graph nodes. ++ */ ++struct node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag that is utilized for "pruning" filters once the complete filter ++ // graph is constructed ++ bool pruned; ++ ++ // List of neighbours ++ neighbour_list_item* neighbours; ++ ++ // Next item in list of graph nodes ++ node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a graph node. ++ */ ++struct neighbour_list_item { ++ // Pointer to neighbour node within list of graph nodes ++ node_list_item* node; ++ ++ // Weight of filter graph's edge between neighbouring nodes ++ int weight; ++ ++ // Flow through filter graph's edge between neighbouring nodes ++ int flow; ++ ++ // List of filters that specify prefixes of neighbouring nodes ++ filter_list_item* filters; ++ ++ // Next item in list of neighbours ++ neighbour_list_item* next; ++}; ++ ++/* ++ * A Structure representing an item in a list of filters that specify prefixes ++ * of neighbouring graph nodes. ++ */ ++struct filter_list_item { ++ // Pointer to representation of filter ++ // (struct filter is defined in stdinc.h included in custom_db.cc) ++ const struct filter* filter; ++ ++ // Next item in list of filters ++ filter_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a set of filters as a filter graph -- i.e., ++ * weighted directed bipartite graph with special source (s) and terminate (t) ++ * nodes -- that is constructed according to filters' source and destination ++ * prefixes and pruned source and destination prefix tries. ++ */ ++class Filter_graph { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the filter graph. ++ */ ++ node_list_item* src_nodes; ++ node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the filter graph. ++ */ ++ node_list_item* s_node; ++ node_list_item* t_node; ++ ++ /* ++ * Private static function that creates deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as all sublists) and sets the value of their components ++ * according to this original list. The only exception is pointer to ++ * neighbour node, which is initialized to NULL (it points to different ++ * list, thus it cannot be initialized to correct value during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static node_list_item* copy_node_list(const node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given node list and all its sublists and ++ * starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to pointer to node list that is to be ++ * deallocated. ++ */ ++ static void remove_node_list(node_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ * The function traverses the given neighbour list and all its sublists ++ * and starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @param Pointer to pointer to the neighbour list that is to be ++ * deallocated. ++ */ ++ static void remove_neighbour_list(neighbour_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole filter ++ * list. ++ * The function traverses the given filter list and deallocates all the ++ * traversed list items. ++ * @param Pointer to pointer to the filter list that is to be ++ * deallocated. ++ */ ++ static void remove_filter_list(filter_list_item** list); ++ ++ /* ++ * Private static function that sets correct values of neighbour node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in orig and src ++ * node lists. For each neighbour node from orig list it looks for ++ * corresponding item in dst node list and stores pointer to this node to ++ * current item in src list. ++ * @param orig Pointer to the constant original node list. ++ * @param src Pointer to the list of source nodes (neighbour node ++ * pointers of this list are set). ++ * @param dst Pointer to the list of destination nodes (nodes of this ++ * list act as targets of neighbour node pointers within ++ * src node list). ++ */ ++ static void set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of node that the ++ * function looks for in the list. ++ * @param list Pointer to list of nodes that is traversed during ++ * looking for node with the given IP prefix. ++ * @return Pointer to found node or NULL. ++ */ ++ static node_list_item* find_node(const IP_prefix& prefix, ++ node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static neighbour_list_item* find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ * @param filter Pointer to the constant filter that is referenced by ++ * the filter node the function looks for in the list. ++ * @param list Pointer to the list of filter nodes that is traversed ++ * during looking for a node pointing to the given ++ * filter. ++ * @return Pointer to the found filter node or NULL. ++ */ ++ static filter_list_item* find_filter(const struct filter* filter, ++ filter_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node corresponding to ++ * the given prefix node at the beginning of the given list of ++ * neighbour nodes. ++ * @param neighbour Pointer to a prefix node whose neighbour node is ++ * going to be inserted. ++ * @param list Pointer to pointer to the list of neighbours that ++ * is going to be extended by the inserted node. ++ */ ++ static void insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list); ++ ++ /* ++ * Private static function that inserts a filter node pointing to the ++ * given filter at the beginning of the given list of filter nodes. ++ * @param node Pointer to the constant filter that is going to be ++ * referenced by the inserted filter node. ++ * @param list Pointer to pointer to the list of filters that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_filter(const struct filter* filter, ++ filter_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const node_list_item* nodes); ++ ++ /* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ * The function performs the specified function on all nodes of the ++ * filter graph (i.e., source and destination nodes as well as the 's' ++ * and 't' nodes). ++ * The function expects that neighbours list referenced from the ++ * non-pruned nodes have been correctly deallocated before calling this ++ * function. ++ */ ++ void remove_and_reset(); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Filter_graph(); ++ ++ /* ++ * Copy constructor. ++ * All pointers are initialized to a deep copy of corresponding members ++ * of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Filter_graph(const Filter_graph& orig); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Filter_graph(); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Filter_graph& operator= (const Filter_graph& copy); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Modifies filter graph to add the specified filter into the set of ++ * filters represented by the graph. ++ * The function searches src_nodes and dst_nodes lists for nodes ++ * representing source and destination prefixes of the given filter and ++ * inserts such nodes into these lists if they are not found. Next, the ++ * function seraches neighbours list of source prefix node for neighbour ++ * node representing destination prefix of the given filter and inserts ++ * such neighbour node into the list if it is not found. Finally, the ++ * function searches filters list of neighbouring node for pointer to the ++ * given filter and inserts such pointer into the list if it is not ++ * found. Along with inserting new filter pointer to the list, the ++ * function increments weight item of neighbouring node representation. ++ * @param filter Pointer to a constant structure representing inserted ++ * filter. ++ */ ++ void add_filter(const struct filter* filter); ++ ++ /* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ * First of all, the function checks whether the 's' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the 's' node for a ++ * neighbour node representing the given prefix. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned source trie are ++ * added using this function. In such a case the source nodes list always ++ * contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * target node of the edge from the 's' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_s_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the ++ * given value. ++ * First of all, the function checks whether the 't' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the node ++ * representing the given prefix within the destination nodes list for a ++ * neighbour node representing the 't' node. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned destination trie ++ * are added using this function. In such a case the destination nodes ++ * list always contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * source node of the edge towards the 't' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_t_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ * First of all, the function removes all edges representing filters with ++ * at least one non-pruned prefix and all nodes representing non-pruned ++ * prefixes. During this step, the "pruned" flag of the remaining nodes ++ * is also set to false. Next, the filter graph is traversed in a BFS ++ * manner and the "pruned" flag is set to true for all visited nodes with ++ * at least one input edge and one output edge. Finally, the function ++ * removes all edges going from the 's' node/to the 't' node that do not ++ * end/start in a node with the set "pruned" flag. These non-pruned nodes ++ * are also removed from the graph in this final step. ++ * The function expects that all steps of the filter graph construction ++ * (i.e., adding filters, s-prefixes, and t-prefixes) have already been ++ * performed before its invocation. ++ */ ++ void to_flow_network(); ++ ++ /* ++ * Computes maximum flow using Dinic's algorithm. ++ * The function builds a flow network corresponding to the filter graph, ++ * transforms it to a level graph and updates the flow through the filter ++ * graph according to a blocking flow through the level graph. This way ++ * the flow through the filter graph is iteratively updated until there ++ * are paths from the 's' node to the 't' node in the level graph. ++ * The flow network is represented by an object of the Flow_network, ++ * which also allows transformation into the corresponding level graph. ++ * @return The value of the maximum flow through the filter graph. ++ */ ++ int max_flow(); ++ ++ /* ++ * Prints the filter graph. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/flow_network.cc b/flow_network.cc +new file mode 100644 +index 0000000..b5523da +--- /dev/null ++++ b/flow_network.cc +@@ -0,0 +1,592 @@ ++// flow_network.cc: Flow_network class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "flow_network.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions (related to filter graph) ************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++net_node_list_item* Flow_network::copy_node_list(const net_node_list_item* orig) { ++ // initialize pointer to copied node list ++ net_node_list_item* result = (orig == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // node list level of copying ++ net_node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->visited = orig->visited; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // neighbour list level of copying ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->src_node = copy; ++ copy_neighbours->dst_node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->capacity = orig_neighbours->capacity; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->orig_edge = orig_neighbours->orig_edge; ++ copy_neighbours->forward_edge = orig_neighbours->forward_edge; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Flow_network::remove_node_list(net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ net_neighbour_list_item* neighbours = list->neighbours; ++ ++ // traverse all neighbours ++ while (neighbours != NULL) { ++ // move to the next neighbour list item and deallocate the current one ++ net_neighbour_list_item* current_neighbour = neighbours; ++ neighbours = neighbours->next; ++ delete current_neighbour; ++ } ++ ++ // move to the next node list item and deallocate the current one ++ net_node_list_item* current_node = list; ++ list = list->next; ++ delete current_node; ++ } ++ ++ return; ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ */ ++void Flow_network::set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next) { ++ // traverse all nodes ++ while (orig != NULL) { ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct destination node pointer ++ if (orig_neighbours->forward_edge) { // forward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, next); ++ } else { // backward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, prev); ++ } ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ copy_neighbours = copy_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ copy = copy->next; ++ } ++ ++ return; ++} // end set_destination_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++net_node_list_item* Flow_network::find_node(const IP_prefix& prefix, ++ net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++net_neighbour_list_item* Flow_network::find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->dst_node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Flow_network::insert_node(const IP_prefix& prefix, ++ net_node_list_item** list) { ++ // allocate and initialize new prefix node ++ net_node_list_item* node = new net_node_list_item; ++ node->prefix = prefix; ++ node->visited = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node representing an edge ++ * between the given source and destination nodes at the beginning of the ++ * specified list of neighbour nodes. ++ */ ++void Flow_network::insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ net_neighbour_list_item* node = new net_neighbour_list_item; ++ node->src_node = src_node; ++ node->dst_node = dst_node; ++ node->capacity = capacity; ++ node->flow = flow; ++ node->orig_edge = orig_edge; ++ node->forward_edge = forward_edge; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ */ ++void Flow_network::print_node_list(const net_node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ net_neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> "; ++ if (neighbours->forward_edge) { // forward edge ++ cout << "FORWARD: "; ++ } else { // backward edge ++ cout << "BACKWARD: "; ++ } ++ cout << neighbours->src_node->prefix.get_prefix() << "/" ++ << neighbours->src_node->prefix.get_length() ++ << " --> " ++ << neighbours->dst_node->prefix.get_prefix() << "/" ++ << neighbours->dst_node->prefix.get_length() ++ << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->capacity ++ << ")" << endl; ++ // move to the next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Flow_network::Flow_network() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Flow_network() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Flow_network::Flow_network(const Flow_network& orig) { ++ // acquire members of the original object ++ const net_node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const net_node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const net_node_list_item* orig_s_node = orig.get_s_node(); ++ const net_node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(orig_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(orig_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(orig_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(orig_s_node, s_node, NULL, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Flow_network& Flow_network::operator=(const Flow_network& copy) { ++ // destruct the original object ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++ ++ // acquire members of the copied object ++ const net_node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const net_node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const net_node_list_item* copy_s_node = copy.get_s_node(); ++ const net_node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(copy_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(copy_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(copy_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(copy_s_node, s_node, NULL, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Destructor. ++ */ ++Flow_network::~Flow_network() { ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++} // end ~Flow_network() ++ ++ ++/* ++ * Adds an edge to the flow network. ++ */ ++void Flow_network::add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity) { ++ // get pointer to correct source node list pointer ++ net_node_list_item** src_list_ptr; ++ switch (src_list) { ++ case 0 : ++ src_list_ptr = &s_node; ++ break; ++ case 1 : ++ src_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ src_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ src_list_ptr = &t_node; ++ break; ++ } ++ ++ // get pointer to correct destination node list pointer ++ net_node_list_item** dst_list_ptr; ++ switch (dst_list) { ++ case 0 : ++ dst_list_ptr = &s_node; ++ break; ++ case 1 : ++ dst_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ dst_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ dst_list_ptr = &t_node; ++ break; ++ } ++ ++ // find source prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* src_node = find_node(src_prefix, *src_list_ptr); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_prefix, src_list_ptr); ++ src_node = *src_list_ptr; ++ } ++ ++ // find destination prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* dst_node = find_node(dst_prefix, *dst_list_ptr); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_prefix, dst_list_ptr); ++ dst_node = *dst_list_ptr; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ net_neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(src_node, dst_node, capacity, 0, orig_edge, ++ forward_edge, &(src_node->neighbours)); ++ } ++} // end add_edge() ++ ++ ++/* ++ * Transforms the flow network into a level graph. ++ */ ++void Flow_network::to_level_graph() { ++ ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ if (s_node != NULL) { ++ s_node->visited = true; ++ q.push(s_node); ++ } ++ ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ net_node_list_item* node = q.front(); ++ q.pop(); ++ // iterate through the list of node's neighbours ++ net_neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ // push a pointer to a pointer to the edge on the stack ++ s.push(neighbour_ptr); ++ // if it has not been visited yet, enqueue a pointer to the target ++ // node of this edge ++ if ((*neighbour_ptr)->dst_node->visited == false) { ++ (*neighbour_ptr)->dst_node->visited = true; ++ q.push((*neighbour_ptr)->dst_node); ++ } ++ // move to the next neighbour ++ neighbour_ptr = &((*neighbour_ptr)->next); ++ } ++ } ++ ++ // initialize a set of level graph nodes with the 't' node ++ list l; ++ l.push_front(t_node); ++ ++ // do an inverse breadth-first search ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // check if the dst_node already belongs to the level graph ++ net_node_list_item* dst_node = (*neighbour_ptr)->dst_node; ++ list::iterator i; ++ for (i = l.begin(); i != l.end(); ++i) { ++ if (*i == dst_node) { ++ break; ++ } ++ } ++ if (i != l.end()) { // dst_node belongs to the level graph ++ // add also src_node to the level graph ++ l.push_front((*neighbour_ptr)->src_node); ++ } else { // dst_node does not belong to the level graph ++ // remove the edge from the flow network ++ net_neighbour_list_item* edge = (*neighbour_ptr); ++ *neighbour_ptr = (*neighbour_ptr)->next; ++ delete edge; ++ } ++ } ++} // end to_level_graph() ++ ++ ++/* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ */ ++int Flow_network::find_blocking_flow() { ++ // check if the flow network exists at all ++ if (s_node == NULL) { ++ return 0; ++ } ++ ++ int blocking_flow = 0; ++ while (1) { // inifinite loop with return statement inside ++ // initialize auxiliary variables ++ stack s; ++ stack s_capacity; ++ net_node_list_item* node = s_node; ++ // do a depth-first search ++ while (node != t_node) { ++ while (node->neighbours == NULL) { // no output edges - traverse back ++ if (s.empty()) { // the stack is empty - no way to traverse back ++ return blocking_flow; ++ } ++ // traverse back along the edge on the top of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ node = neighbour->src_node; ++ // pop the top elements of both stacks ++ s.pop(); ++ s_capacity.pop(); ++ // remove back-traversed edge ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ // push the first edge of the current node and its remaining capacity on ++ // the respective stacks ++ s.push(&(node->neighbours)); ++ s_capacity.push(node->neighbours->capacity - node->neighbours->flow); ++ // move forward along the edge - update the current node ++ node = node->neighbours->dst_node; ++ } ++ ++ // determine the smallest capacity among edges of the found path ++ int min_capacity = s_capacity.top(); ++ s_capacity.pop(); ++ while (!s_capacity.empty()) { ++ // pop the top element of the capacity stack ++ int capacity = s_capacity.top(); ++ s_capacity.pop(); ++ if (capacity < min_capacity) { // update the smallest capacity ++ min_capacity = capacity; ++ } ++ } ++ ++ // update the flow through the found path according to min_capacity value ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // update the flow in both the flow network and filter graph ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ neighbour->flow += min_capacity; ++ if (neighbour->forward_edge) { // forward edge ++ neighbour->orig_edge->flow += min_capacity; ++ } else { // backward edge ++ neighbour->orig_edge->flow -= min_capacity; ++ } ++ // remove the edge if its remaining capacity decreases to 0 ++ if (neighbour->capacity == neighbour->flow) { ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ } ++ ++ // update the value of blocking flow through the flow network ++ blocking_flow += min_capacity; ++ } ++} // end find_blocking_flow() ++ ++ ++/* ++ * Prints the flow network. ++ */ ++void Flow_network::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/flow_network.h b/flow_network.h +new file mode 100644 +index 0000000..df76c3f +--- /dev/null ++++ b/flow_network.h +@@ -0,0 +1,362 @@ ++// flow_network.h: header file for Flow_network class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FLOW_NETWORK_H ++#define FLOW_NETWORK_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++#include "filter_graph.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct net_node_list_item net_node_list_item; ++typedef struct net_neighbour_list_item net_neighbour_list_item; ++ ++/* ++ * A structure representing an item in a list of network nodes. ++ */ ++struct net_node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag showing whether the node was already visited during a traversal ++ bool visited; ++ ++ // List of neighbours ++ net_neighbour_list_item* neighbours; ++ ++ // Next item in list of network nodes ++ net_node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a network node. ++ */ ++struct net_neighbour_list_item { ++ // Pointer to source node within list of network nodes ++ net_node_list_item* src_node; ++ ++ // Pointer to destination node within list of network nodes ++ net_node_list_item* dst_node; ++ ++ // Residual capacity of flow network's edge between neighbouring nodes ++ int capacity; ++ ++ // Flow through flow network's edge between neighbouring nodes ++ int flow; ++ ++ // Pointer to corresponding edge in filter graph ++ // (the pointer is the same for both forward and backward edges) ++ neighbour_list_item* orig_edge; ++ ++ // Flag showing whether this node represents a forward edge ++ bool forward_edge; ++ ++ // Next item in list of neighbours ++ net_neighbour_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a flow network -- i.e., weighted directed graph ++ * with special source (s) and terminate (t) nodes -- over a filter graph. ++ */ ++class Flow_network { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the flow network. ++ */ ++ net_node_list_item* src_nodes; ++ net_node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the flow network. ++ */ ++ net_node_list_item* s_node; ++ net_node_list_item* t_node; ++ ++ /* ++ * Private static function that creates a deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as their neighbours sublists) and sets the value of their ++ * components according to this original list. The only exception is a ++ * pointer to destination node, which is initialized to NULL (it points ++ * to different list, thus it cannot be initialized to correct value ++ * during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static net_node_list_item* copy_node_list(const net_node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given list and all its sublists and ++ * starting from lists of neighbours it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to node list that is to be deallocated. ++ */ ++ static void remove_node_list(net_node_list_item* list); ++ ++ /* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in the orig and ++ * copy node lists. For each destination node from the orig list it looks ++ * for a corresponding item in either prev (backward edges) or next ++ * (forward edges) node list and stores the pointer to this node to the ++ * current item in the copy list. ++ * @param orig Pointer to the constant original node list. ++ * @param copy Pointer to the copy of the original node list ++ * (destination node pointers of this list are set). ++ * @param prev Pointer to the list of destination nodes of backward ++ * edges. ++ * @param next Pointer to the list of destination nodes of forward ++ * edges. ++ */ ++ static void set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for a node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of the node that the ++ * function looks for in the list. ++ * @param list Pointer to the list of nodes that is traversed during ++ * looking for the node with the given IP prefix. ++ * @return Pointer to the found node or NULL. ++ */ ++ static net_node_list_item* find_node(const IP_prefix& prefix, ++ net_node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static net_neighbour_list_item* find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ net_node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node representing an ++ * edge between the given source and destination nodes at the beginning ++ * of the specified list of neighbour nodes. ++ * @param src_node Pointer to a source node of the represented ++ * edge. ++ * @param dst_node Pointer to a destination node of the represented ++ * edge. ++ * @param capacity Residual capacity of the represented edge. ++ * @param flow Flow through the represented edge. ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the inserted neighbour ++ * represents a forward edge. ++ * @param list Pointer to pointer to the list of neighbours ++ * that is going to be extended by the inserted ++ * node. ++ */ ++ static void insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const net_node_list_item* nodes); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Flow_network(); ++ ++ /* ++ * Copy constructor. ++ * All pointers used by the filter graph are initialized to a deep copy ++ * of corresponding members of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Flow_network(const Flow_network& orig); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in a similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Flow_network& operator= (const Flow_network& copy); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Flow_network(); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const net_node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const net_node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const net_node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const net_node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Adds an edge to the flow network. ++ * First of all, if they are not already present, the function inserts ++ * nodes representing src_prefix and dst_prefix into node lists src_list ++ * and dst_list, respectively. Next, if it is not already present, the ++ * function inserts a neighbour node representing the edge into the list ++ * of neighbours of the node representing the source prefix. Flow item of ++ * the neighbour node is set to 0, while other items within its structure ++ * are set according to the function's parameters. ++ * @param src_prefix Reference to the IP_prefix object that ++ * determines a source node of the added edge. ++ * @param src_list Specification of a node list that contains the ++ * source node of the added edge. Mapping of the ++ * four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param dst_prefix Reference to the IP_prefix object that ++ * determines a destination node of the added edge. ++ * @param dst_list Specification of a node list that contains the ++ * destination node of the added edge. Mapping of ++ * the four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the added edge represents a ++ * forward edge. ++ * @param capacity Residual capacity of the added edge. ++ */ ++ void add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity); ++ ++ /* ++ * Transforms the flow network into a level graph. ++ * During inverse BFS of the flow network, starting from a set containing ++ * the 't' node, the function incrementally extends the set by start ++ * nodes of edges ending in one of the set nodes and removes from the ++ * flow network edges that do not meet this condition. ++ */ ++ void to_level_graph(); ++ ++ /* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ * The function repeatedly performs DST to find an s-t path in the flow ++ * network and the smallest capacity on this path. Once the function ++ * reaches the 't' node, it returns along the found path and increases ++ * the flow through the particular flow network edges as well as the ++ * corresponding filter graph edges. The function also updates capacities ++ * of backward-traversed flow network edges and removes them in case ++ * their capacity decreases to 0. In case of DFS ending in a node other ++ * than the 't' node, the function traverses back to the closest node ++ * with at least two output edges and removes all back-traversed edges. ++ * After each successful DFS and flow update on the found path, the ++ * function increases the value of the total flow through the flow ++ * network, which is returned at the end. ++ * The function expects that the flow network is in the form of a level ++ * graph at the time of invocation. ++ * @return The value of the blocking flow through the flow network. ++ */ ++ int find_blocking_flow(); ++ ++ /* ++ * Prints the flow network. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/ip-address/COPYING b/ip-address/COPYING +new file mode 100644 +index 0000000..03fc9f6 +--- /dev/null ++++ b/ip-address/COPYING +@@ -0,0 +1,4 @@ ++Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++ ++Distributed under the Boost Software License, Version 1.0. (See accompanying ++file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +diff --git a/ip-address/LICENSE_1_0.txt b/ip-address/LICENSE_1_0.txt +new file mode 100644 +index 0000000..36b7cd9 +--- /dev/null ++++ b/ip-address/LICENSE_1_0.txt +@@ -0,0 +1,23 @@ ++Boost Software License - Version 1.0 - August 17th, 2003 ++ ++Permission is hereby granted, free of charge, to any person or organization ++obtaining a copy of the software and accompanying documentation covered by ++this license (the "Software") to use, reproduce, display, distribute, ++execute, and transmit the Software, and to prepare derivative works of the ++Software, and to permit third-parties to whom the Software is furnished to ++do so, all subject to the following: ++ ++The copyright notices in the Software and this entire statement, including ++the above license grant, this restriction and the following disclaimer, ++must be included in all copies of the Software, in whole or in part, and ++all derivative works of the Software, unless such copies or derivative ++works are solely in the form of machine-executable object code generated by ++a source language processor. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. +diff --git a/ip-address/README.md b/ip-address/README.md +new file mode 100644 +index 0000000..08ff928 +--- /dev/null ++++ b/ip-address/README.md +@@ -0,0 +1,18 @@ ++IP Address Proposal ++=================== ++ ++Proposed IP addresses classes for the standard C++ library. ++ ++What's Included ++--------------- ++ ++* `./include` - Reference implementation. ++ ++Tested Platforms ++---------------- ++ ++* Mac OS 10.8 using g++ 4.7 (requires `-std=c++11`) ++* Mac OS 10.8 using clang++ from Xcode 4.6 (requires `-std=c++11` and `-stdlib=libc++`) ++* Linux (CentOS 6.2) using g++ 4.7 (requires `-std=c++11`) ++* Windows 7 32-bit using Visual Studio 2010 ++* Windows 7 x64 using Visual Studio 2010 +diff --git a/ip-address/include/network b/ip-address/include/network +new file mode 100644 +index 0000000..c97ea69 +--- /dev/null ++++ b/ip-address/include/network +@@ -0,0 +1,25 @@ ++// ++// network ++// ~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_NETWORK_HEADER_FILE ++#define STDNET_NETWORK_HEADER_FILE ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/address_cast.hpp" ++#include "std/net/literals.hpp" ++ ++#endif // STDNET_NETWORK_HEADER_FILE +diff --git a/ip-address/include/std/net/detail/config.hpp b/ip-address/include/std/net/detail/config.hpp +new file mode 100644 +index 0000000..c797490 +--- /dev/null ++++ b/ip-address/include/std/net/detail/config.hpp +@@ -0,0 +1,666 @@ ++// ++// detail/config.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_CONFIG_HPP ++#define STDNET_DETAIL_CONFIG_HPP ++ ++// Default to a header-only implementation. The user must specifically request ++// separate compilation by defining either STDNET_SEPARATE_COMPILATION or ++// STDNET_DYN_LINK (as a DLL/shared library implies separate compilation). ++#if !defined(STDNET_HEADER_ONLY) ++# if !defined(STDNET_SEPARATE_COMPILATION) ++# if !defined(STDNET_DYN_LINK) ++# define STDNET_HEADER_ONLY 1 ++# endif // !defined(STDNET_DYN_LINK) ++# endif // !defined(STDNET_SEPARATE_COMPILATION) ++#endif // !defined(STDNET_HEADER_ONLY) ++ ++#if defined(STDNET_HEADER_ONLY) ++# define STDNET_DECL inline ++#else // defined(STDNET_HEADER_ONLY) ++# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++// We need to import/export our code only if the user has specifically asked ++// for it by defining STDNET_DYN_LINK. ++# if defined(STDNET_DYN_LINK) ++// Export if this is our own source, otherwise import. ++# if defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllexport) ++# else // defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllimport) ++# endif // defined(STDNET_SOURCE) ++# endif // defined(STDNET_DYN_LINK) ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++#endif // defined(STDNET_HEADER_ONLY) ++ ++// If STDNET_DECL isn't defined yet define it now. ++#if !defined(STDNET_DECL) ++# define STDNET_DECL ++#endif // !defined(STDNET_DECL) ++ ++// Microsoft Visual C++ detection. ++#if !defined(STDNET_MSVC) ++# if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++# define STDNET_MSVC _MSC_VER ++# endif // defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++#endif // defined(STDNET_MSVC) ++ ++// Support move construction and assignment on compilers known to allow it. ++#if !defined(STDNET_HAS_MOVE) ++# if !defined(STDNET_DISABLE_MOVE) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_MOVE 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_MOVE) ++#endif // !defined(STDNET_HAS_MOVE) ++ ++// If STDNET_MOVE_CAST isn't defined, and move support is available, define ++// STDNET_MOVE_ARG and STDNET_MOVE_CAST to take advantage of rvalue ++// references and perfect forwarding. ++#if defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++# define STDNET_MOVE_ARG(type) type&& ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++ ++// If STDNET_MOVE_CAST still isn't defined, default to a C++03-compatible ++// implementation. Note that older g++ and MSVC versions don't like it when you ++// pass a non-member function through a const reference, so for most compilers ++// we'll play it safe and stick with the old approach of passing the handler by ++// value. ++#if !defined(STDNET_MOVE_CAST) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) const type& ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) type ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# elif defined(STDNET_MSVC) ++# if (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) const type& ++# else // (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) type ++# endif // (_MSC_VER >= 1400) ++# else ++# define STDNET_MOVE_ARG(type) type ++# endif ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // !defined_STDNET_MOVE_CAST ++ ++// Support variadic templates on compilers known to allow it. ++#if !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++# if !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_variadic_templates) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# endif // !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++#endif // !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++// Support the noexcept specifier on compilers known to allow it. ++#if !defined(STDNET_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_NOEXCEPT noexcept ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_NOEXCEPT noexcept ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_NOEXCEPT) ++# define STDNET_NOEXCEPT ++# endif // !defined(STDNET_NOEXCEPT) ++#endif // !defined(STDNET_NOEXCEPT) ++ ++// Support deleted functions on compilers known to allow it. ++#if !defined(STDNET_DELETED) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_DELETED = delete ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_deleted_functions) ++# define STDNET_DELETED = delete ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_DELETED) ++# define STDNET_DELETED ++# endif // !defined(STDNET_DELETED) ++#endif // !defined(STDNET_DELETED) ++ ++// Support relaxed constexpr on compilers known to allow it. ++#if !defined(STDNET_CONSTEXPR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_constexpr) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // __has_feature(cxx_constexpr) ++# endif // defined(__clang__) ++# if !defined(STDNET_CONSTEXPR) ++# define STDNET_CONSTEXPR ++# endif // !defined(STDNET_CONSTEXPR) ++#endif // !defined(STDNET_CONSTEXPR) ++ ++// Standard library support for system errors. ++#if !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++# if !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SYSTEM_ERROR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++#endif // !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++ ++// Compliant C++11 compilers put noexcept specifiers on error_category members. ++#if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT ++# endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++#endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++ ++// Standard library support for arrays. ++#if !defined(STDNET_HAS_STD_ARRAY) ++# if !defined(STDNET_DISABLE_STD_ARRAY) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_ARRAY) ++#endif // !defined(STDNET_HAS_STD_ARRAY) ++ ++// Standard library support for shared_ptr and weak_ptr. ++#if !defined(STDNET_HAS_STD_SHARED_PTR) ++# if !defined(STDNET_DISABLE_STD_SHARED_PTR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_SHARED_PTR) ++#endif // !defined(STDNET_HAS_STD_SHARED_PTR) ++ ++// Standard library support for atomic operations. ++#if !defined(STDNET_HAS_STD_ATOMIC) ++# if !defined(STDNET_DISABLE_STD_ATOMIC) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ATOMIC 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ATOMIC) ++#endif // !defined(STDNET_HAS_STD_ATOMIC) ++ ++// Standard library support for chrono. Some standard libraries (such as the ++// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x ++// drafts, rather than the eventually standardised name of steady_clock. ++#if !defined(STDNET_HAS_STD_CHRONO) ++# if !defined(STDNET_DISABLE_STD_CHRONO) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_CHRONO 1 ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# define STDNET_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_CHRONO) ++#endif // !defined(STDNET_HAS_STD_CHRONO) ++ ++// Standard library support for addressof. ++#if !defined(STDNET_HAS_STD_ADDRESSOF) ++# if !defined(STDNET_DISABLE_STD_ADDRESSOF) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ADDRESSOF 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ADDRESSOF) ++#endif // !defined(STDNET_HAS_STD_ADDRESSOF) ++ ++// Standard library support for the function class. ++#if !defined(STDNET_HAS_STD_FUNCTION) ++# if !defined(STDNET_DISABLE_STD_FUNCTION) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_FUNCTION 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_FUNCTION) ++#endif // !defined(STDNET_HAS_STD_FUNCTION) ++ ++// Standard library support for type traits. ++#if !defined(STDNET_HAS_STD_TYPE_TRAITS) ++# if !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_TYPE_TRAITS 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++#endif // !defined(STDNET_HAS_STD_TYPE_TRAITS) ++ ++// Standard library support for the cstdint header. ++#if !defined(STDNET_HAS_CSTDINT) ++# if !defined(STDNET_DISABLE_CSTDINT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CSTDINT 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_CSTDINT) ++#endif // !defined(STDNET_HAS_CSTDINT) ++ ++// Windows target. ++#if !defined(STDNET_WINDOWS) ++# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++# define STDNET_WINDOWS 1 ++# endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++#endif // !defined(STDNET_WINDOWS) ++ ++// Windows: target OS version. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma message( \ ++ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ ++ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ ++ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ ++ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") ++# else // defined(_MSC_VER) || defined(__BORLANDC__) ++# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. ++# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. ++# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# define _WIN32_WINNT 0x0501 ++# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) ++# if defined(_WIN32) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(_WIN32) && !defined(WIN32) ++# endif // defined(_MSC_VER) ++# if defined(__BORLANDC__) ++# if defined(__WIN32__) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(__WIN32__) && !defined(WIN32) ++# endif // defined(__BORLANDC__) ++# if defined(__CYGWIN__) ++# if !defined(__USE_W32_SOCKETS) ++# error You must add -D__USE_W32_SOCKETS to your compiler options. ++# endif // !defined(__USE_W32_SOCKETS) ++# endif // defined(__CYGWIN__) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: minimise header inclusion. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++# if !defined(WIN32_LEAN_AND_MEAN) ++# define WIN32_LEAN_AND_MEAN ++# endif // !defined(WIN32_LEAN_AND_MEAN) ++# endif // !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: suppress definition of "min" and "max" macros. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_NOMINMAX) ++# if !defined(NOMINMAX) ++# define NOMINMAX 1 ++# endif // !defined(NOMINMAX) ++# endif // !defined(STDNET_NO_NOMINMAX) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: No ANSI API calls. ++#if !defined(STDNET_NO_ANSI_APIS) ++# if defined(STDNET_WINDOWS) && defined(UNDER_CE) ++# define STDNET_NO_ANSI_APIS 1 ++# endif // defined(STDNET_WINDOWS) && defined(UNDER_CE) ++#endif // !defined(STDNET_NO_ANSI_APIS) ++ ++// Windows: IO Completion Ports. ++#if !defined(STDNET_HAS_IOCP) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# if !defined(UNDER_CE) ++# if !defined(STDNET_DISABLE_IOCP) ++# define STDNET_HAS_IOCP 1 ++# endif // !defined(STDNET_DISABLE_IOCP) ++# endif // !defined(UNDER_CE) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_IOCP) ++ ++// Linux: epoll, eventfd and timerfd. ++#if defined(__linux__) ++# include ++# if !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_DISABLE_EPOLL) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# define STDNET_HAS_EPOLL 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# endif // !defined(STDNET_DISABLE_EPOLL) ++# endif // !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_DISABLE_EVENTFD) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# define STDNET_HAS_EVENTFD 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# endif // !defined(STDNET_DISABLE_EVENTFD) ++# endif // !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_HAS_TIMERFD) ++# if defined(STDNET_HAS_EPOLL) ++# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# define STDNET_HAS_TIMERFD 1 ++# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# endif // defined(STDNET_HAS_EPOLL) ++# endif // !defined(STDNET_HAS_TIMERFD) ++#endif // defined(__linux__) ++ ++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. ++#if (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) ++# if !defined(STDNET_HAS_KQUEUE) ++# if !defined(STDNET_DISABLE_KQUEUE) ++# define STDNET_HAS_KQUEUE 1 ++# endif // !defined(STDNET_DISABLE_KQUEUE) ++# endif // !defined(STDNET_HAS_KQUEUE) ++#endif // (defined(__MACH__) && defined(__APPLE__)) ++ // || defined(__FreeBSD__) ++ // || defined(__NetBSD__) ++ // || defined(__OpenBSD__) ++ ++// Solaris: /dev/poll. ++#if defined(__sun) ++# if !defined(STDNET_HAS_DEV_POLL) ++# if !defined(STDNET_DISABLE_DEV_POLL) ++# define STDNET_HAS_DEV_POLL 1 ++# endif // !defined(STDNET_DISABLE_DEV_POLL) ++# endif // !defined(STDNET_HAS_DEV_POLL) ++#endif // defined(__sun) ++ ++// Serial ports. ++#if !defined(STDNET_HAS_SERIAL_PORT) ++# if defined(STDNET_HAS_IOCP) \ ++ || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(STDNET_DISABLE_SERIAL_PORT) ++# define STDNET_HAS_SERIAL_PORT 1 ++# endif // !defined(STDNET_DISABLE_SERIAL_PORT) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(STDNET_HAS_IOCP) ++ // || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_SERIAL_PORT) ++ ++// Windows: stream handles. ++#if !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_STREAM_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++ ++// Windows: random access handles. ++#if !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++ ++// Windows: object handles. ++#if !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_WINDOWS_OBJECT_HANDLE 1 ++# endif // !defined(UNDER_CE) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++ ++// Windows: OVERLAPPED wrapper. ++#if !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++# if !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_OVERLAPPED_PTR 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++#endif // !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++ ++// POSIX: stream-oriented file descriptors. ++#if !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_POSIX_STREAM_DESCRIPTOR 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++#endif // !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++ ++// UNIX domain sockets. ++#if !defined(STDNET_HAS_LOCAL_SOCKETS) ++# if !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_LOCAL_SOCKETS 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++#endif // !defined(STDNET_HAS_LOCAL_SOCKETS) ++ ++// Can use sigaction() instead of signal(). ++#if !defined(STDNET_HAS_SIGACTION) ++# if !defined(STDNET_DISABLE_SIGACTION) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_SIGACTION 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_SIGACTION) ++#endif // !defined(STDNET_HAS_SIGACTION) ++ ++// Can use signal(). ++#if !defined(STDNET_HAS_SIGNAL) ++# if !defined(STDNET_DISABLE_SIGNAL) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_SIGNAL 1 ++# endif // !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SIGNAL) ++#endif // !defined(STDNET_HAS_SIGNAL) ++ ++// Whether standard iostreams are disabled. ++//#if !defined(STDNET_NO_IOSTREAM) ++//# define STDNET_NO_IOSTREAM 1 ++//#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// Whether exception handling is disabled. ++//#if !defined(STDNET_NO_EXCEPTIONS) ++//# define STDNET_NO_EXCEPTIONS 1 ++//#endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++// Whether the typeid operator is supported. ++//#if !defined(STDNET_NO_TYPEID) ++//# define STDNET_NO_TYPEID 1 ++//#endif // !defined(STDNET_NO_TYPEID) ++ ++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to ++// get access to the various platform feature macros, e.g. to be able to test ++// for threads support. ++#if !defined(STDNET_HAS_UNISTD_H) ++# if defined(unix) \ ++ || defined(__unix) \ ++ || defined(_XOPEN_SOURCE) \ ++ || defined(_POSIX_SOURCE) \ ++ || (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) \ ++ || defined(__linux__) ++# define STDNET_HAS_UNISTD_H 1 ++# endif ++#endif // !defined(STDNET_HAS_UNISTD_H) ++#if defined(STDNET_HAS_UNISTD_H) ++# include ++#endif // defined(STDNET_HAS_UNISTD_H) ++ ++// Threads. ++#if !defined(STDNET_HAS_THREADS) ++# if !defined(STDNET_DISABLE_THREADS) ++# if defined(_MSC_VER) && defined(_MT) ++# define STDNET_HAS_THREADS 1 ++# elif defined(__BORLANDC__) && defined(__MT__) ++# define STDNET_HAS_THREADS 1 ++# elif defined(_POSIX_THREADS) ++# define STDNET_HAS_THREADS 1 ++# endif // defined(_MSC_VER) && defined(_MT) ++# endif // !defined(STDNET_DISABLE_THREADS) ++#endif // !defined(STDNET_HAS_THREADS) ++ ++// POSIX threads. ++#if !defined(STDNET_HAS_PTHREADS) ++# if defined(STDNET_HAS_THREADS) ++# if defined(_POSIX_THREADS) ++# define STDNET_HAS_PTHREADS 1 ++# endif // defined(_POSIX_THREADS) ++# endif // defined(STDNET_HAS_THREADS) ++#endif // !defined(STDNET_HAS_PTHREADS) ++ ++// Helper to prevent macro expansion. ++#define STDNET_PREVENT_MACRO_SUBSTITUTION ++ ++// Helper to define in-class constants. ++#if !defined(STDNET_STATIC_CONSTANT) ++# define STDNET_STATIC_CONSTANT(type, assignment) \ ++ static const type assignment ++#endif // !defined(STDNET_STATIC_CONSTANT) ++ ++// Microsoft Visual C++'s secure C runtime library. ++#if !defined(STDNET_HAS_SECURE_RTL) ++# if !defined(STDNET_DISABLE_SECURE_RTL) ++# if defined(STDNET_MSVC) \ ++ && (STDNET_MSVC >= 1400) \ ++ && !defined(UNDER_CE) ++# define STDNET_HAS_SECURE_RTL 1 ++# endif // defined(STDNET_MSVC) ++ // && (STDNET_MSVC >= 1400) ++ // && !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SECURE_RTL) ++#endif // !defined(STDNET_HAS_SECURE_RTL) ++ ++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. ++#if !defined(STDNET_HAS_HANDLER_HOOKS) ++# if !defined(STDNET_DISABLE_HANDLER_HOOKS) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 3) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // (__GNUC__ >= 3) ++# elif !defined(__BORLANDC__) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // !defined(__BORLANDC__) ++# endif // !defined(STDNET_DISABLE_HANDLER_HOOKS) ++#endif // !defined(STDNET_HAS_HANDLER_HOOKS) ++ ++// Support for the __thread keyword extension. ++#if !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++# if defined(__linux__) ++# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# if !defined(__INTEL_COMPILER) && !defined(__ICL) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# endif // defined(__linux__) ++#endif // !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++ ++// Support for POSIX ssize_t typedef. ++#if !defined(STDNET_DISABLE_SSIZE_T) ++# if defined(__linux__) \ ++ || (defined(__MACH__) && defined(__APPLE__)) ++# define STDNET_HAS_SSIZE_T 1 ++# endif // defined(__linux__) ++ // || (defined(__MACH__) && defined(__APPLE__)) ++#endif // !defined(STDNET_DISABLE_SSIZE_T) ++ ++#endif // STDNET_DETAIL_CONFIG_HPP +diff --git a/ip-address/include/std/net/detail/impl/socket_ops.ipp b/ip-address/include/std/net/detail/impl/socket_ops.ipp +new file mode 100644 +index 0000000..13b32a3 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/socket_ops.ipp +@@ -0,0 +1,260 @@ ++// ++// detail/impl/socket_ops.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_IPP ++#define STDNET_DETAIL_SOCKET_OPS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++#if defined(__hpux) ++// HP-UX doesn't declare these functions extern "C", so they are declared again ++// here to avoid linker errors about undefined symbols. ++extern "C" char* if_indextoname(unsigned int, char*); ++extern "C" unsigned int if_nametoindex(const char*); ++#endif // defined(__hpux) ++ ++inline void clear_last_error() ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ WSASetLastError(0); ++#else ++ errno = 0; ++#endif ++} ++ ++template ++inline ReturnType error_wrapper(ReturnType return_value, ++ std::error_code& ec) ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ec = std::error_code(WSAGetLastError(), ++ std::experimental::net::detail::syserrc::system_category()); ++#else ++ ec = std::error_code(errno, ++ std::experimental::net::detail::syserrc::system_category()); ++#endif ++ return return_value; ++} ++ ++const char* inet_ntop(int af, const void* src, char* dest, size_t length, ++ unsigned long scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return 0; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ DWORD address_length; ++ if (af == AF_INET) ++ { ++ address_length = sizeof(sockaddr_in4_type); ++ address.v4.sin_family = AF_INET; ++ address.v4.sin_port = 0; ++ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); ++ } ++ else // AF_INET6 ++ { ++ address_length = sizeof(sockaddr_in6_type); ++ address.v6.sin6_family = AF_INET6; ++ address.v6.sin6_port = 0; ++ address.v6.sin6_flowinfo = 0; ++ address.v6.sin6_scope_id = scope_id; ++ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); ++ } ++ ++ DWORD string_length = static_cast(length); ++#if defined(STDNET_NO_ANSI_APIS) ++ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); ++ int result = error_wrapper(::WSAAddressToStringW(&address.base, ++ address_length, 0, string_buffer, &string_length), ec); ++ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); ++#else ++ int result = error_wrapper(::WSAAddressToStringA( ++ &address.base, address_length, 0, dest, &string_length), ec); ++#endif ++ ++ // Windows may set error code on success. ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ // Windows may not set an error code on failure. ++ else if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ return result == socket_error_retval ? 0 : dest; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ const char* result = error_wrapper(::inet_ntop( ++ af, src, dest, static_cast(length)), ec); ++ if (result == 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result != 0 && af == AF_INET6 && scope_id != 0) ++ { ++ using namespace std; // For strcat and sprintf. ++ char if_name[IF_NAMESIZE + 1] = "%"; ++ const in6_addr_type* ipv6_address = static_cast(src); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (!is_link_local ++ || if_indextoname(static_cast(scope_id), if_name + 1) == 0) ++ sprintf(if_name + 1, "%lu", scope_id); ++ strcat(dest, if_name); ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy and strcmp. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return -1; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ int address_length = sizeof(sockaddr_storage_type); ++#if defined(STDNET_NO_ANSI_APIS) ++ int num_wide_chars = strlen(src) + 1; ++ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ++ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); ++ int result = error_wrapper(::WSAStringToAddressW( ++ wide_buffer, af, 0, &address.base, &address_length), ec); ++#else ++ int result = error_wrapper(::WSAStringToAddressA( ++ const_cast(src), af, 0, &address.base, &address_length), ec); ++#endif ++ ++ if (af == AF_INET) ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); ++ ec = std::error_code(); ++ } ++ else if (strcmp(src, "255.255.255.255") == 0) ++ { ++ static_cast(dest)->s_addr = INADDR_NONE; ++ ec = std::error_code(); ++ } ++ } ++ else // AF_INET6 ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); ++ if (scope_id) ++ *scope_id = address.v6.sin6_scope_id; ++ ec = std::error_code(); ++ } ++ } ++ ++ // Windows may not set an error code on failure. ++ if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ return result == socket_error_retval ? -1 : 1; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ int result = error_wrapper(::inet_pton(af, src, dest), ec); ++ if (result <= 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result > 0 && af == AF_INET6 && scope_id) ++ { ++ using namespace std; // For strchr and atoi. ++ *scope_id = 0; ++ if (const char* if_name = strchr(src, '%')) ++ { ++ in6_addr_type* ipv6_address = static_cast(dest); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (is_link_local) ++ *scope_id = if_nametoindex(if_name + 1); ++ if (*scope_id == 0) ++ *scope_id = atoi(if_name + 1); ++ } ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++u_long_type network_to_host_long(u_long_type value) ++{ ++ return ntohl(value); ++} ++ ++u_long_type host_to_network_long(u_long_type value) ++{ ++ return htonl(value); ++} ++ ++u_short_type network_to_host_short(u_short_type value) ++{ ++ return ntohs(value); ++} ++ ++u_short_type host_to_network_short(u_short_type value) ++{ ++ return htons(value); ++} ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_IPP +diff --git a/ip-address/include/std/net/detail/impl/system_errors.ipp b/ip-address/include/std/net/detail/impl/system_errors.ipp +new file mode 100644 +index 0000000..8b01e08 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/system_errors.ipp +@@ -0,0 +1,94 @@ ++// ++// impl/system_errors.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++#define STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/local_free_on_block_exit.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++class system_category : public std::error_category ++{ ++public: ++ const char* name() const STDNET_ERROR_CATEGORY_NOEXCEPT ++ { ++ return "std.net.system"; ++ } ++ ++ std::string message(int value) const ++ { ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ char* msg = 0; ++ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER ++ | FORMAT_MESSAGE_FROM_SYSTEM ++ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, ++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); ++ detail::local_free_on_block_exit local_free_obj(msg); ++ if (length && msg[length - 1] == '\n') ++ msg[--length] = '\0'; ++ if (length && msg[length - 1] == '\r') ++ msg[--length] = '\0'; ++ if (length) ++ return msg; ++ else ++ return "std.net.system error"; ++#else // defined(STDNET_WINDOWS) ++#if !defined(__sun) ++ if (value == ECANCELED) ++ return "Operation aborted."; ++#endif // !defined(__sun) ++#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) ++ using namespace std; ++ return strerror(value); ++#elif defined(__MACH__) && defined(__APPLE__) \ ++ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ ++ || defined(_AIX) || defined(__hpux) || defined(__osf__) \ ++ || defined(__ANDROID__) ++ char buf[256] = ""; ++ using namespace std; ++ strerror_r(value, buf, sizeof(buf)); ++ return buf; ++#else ++ char buf[256] = ""; ++ return strerror_r(value, buf, sizeof(buf)); ++#endif ++#endif // defined(STDNET_WINDOWS) ++ } ++}; ++ ++} // namespace syserrc ++ ++const std::error_category& system_category() ++{ ++ static syserrc::system_category instance; ++ return instance; ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP +diff --git a/ip-address/include/std/net/detail/impl/throw_error.ipp b/ip-address/include/std/net/detail/impl/throw_error.ipp +new file mode 100644 +index 0000000..92baf1c +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/throw_error.ipp +@@ -0,0 +1,49 @@ ++// ++// detail/impl/throw_error.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++#define STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void do_throw_error(const std::error_code& err) ++{ ++ std::system_error e(err); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++void do_throw_error(const std::error_code& err, const char* location) ++{ ++ std::system_error e(err, location); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_THROW_ERROR_IPP +diff --git a/ip-address/include/std/net/detail/impl/winsock_init.ipp b/ip-address/include/std/net/detail/impl/winsock_init.ipp +new file mode 100644 +index 0000000..7114f6a +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/winsock_init.ipp +@@ -0,0 +1,73 @@ ++// ++// detail/impl/winsock_init.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++#define STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/winsock_init.hpp" ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void winsock_init_base::startup(data& d, ++ unsigned char major, unsigned char minor) ++{ ++ if (::InterlockedIncrement(&d.init_count_) == 1) ++ { ++ WSADATA wsa_data; ++ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); ++ ::InterlockedExchange(&d.result_, result); ++ } ++} ++ ++void winsock_init_base::cleanup(data& d) ++{ ++ if (::InterlockedDecrement(&d.init_count_) == 0) ++ { ++ ::WSACleanup(); ++ } ++} ++ ++void winsock_init_base::throw_on_error(data& d) ++{ ++ long result = ::InterlockedExchangeAdd(&d.result_, 0); ++ if (result != 0) ++ { ++ std::error_code ec(result, ++ std::experimental::net::detail::system_category()); ++ std::experimental::net::detail::throw_error(ec, "winsock"); ++ } ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP +diff --git a/ip-address/include/std/net/detail/local_free_on_block_exit.hpp b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +new file mode 100644 +index 0000000..64c9137 +--- /dev/null ++++ b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +@@ -0,0 +1,63 @@ ++// ++// detail/local_free_on_block_exit.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++#define STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class local_free_on_block_exit ++{ ++public: ++ // Constructor blocks all signals for the calling thread. ++ explicit local_free_on_block_exit(void* p) ++ : p_(p) ++ { ++ } ++ ++ // Destructor restores the previous signal mask. ++ ~local_free_on_block_exit() ++ { ++ ::LocalFree(p_); ++ } ++ ++private: ++ // Disallow copying and assignemnt. ++ local_free_on_block_exit(const local_free_on_block_exit&); ++ local_free_on_block_exit& operator=(const local_free_on_block_exit&); ++ ++ void* p_; ++}; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +diff --git a/ip-address/include/std/net/detail/old_win_sdk_compat.hpp b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +new file mode 100644 +index 0000000..3a3cdac +--- /dev/null ++++ b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +@@ -0,0 +1,218 @@ ++// ++// detail/old_win_sdk_compat.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++#define STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Guess whether we are building against on old Platform SDK. ++#if !defined(IN6ADDR_ANY_INIT) ++#define STDNET_HAS_OLD_WIN_SDK 1 ++#endif // !defined(IN6ADDR_ANY_INIT) ++ ++#if defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Emulation of types that are missing from old Platform SDKs. ++// ++// N.B. this emulation is also used if building for a Windows 2000 target with ++// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support ++// in that case. ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++enum ++{ ++ sockaddr_storage_maxsize = 128, // Maximum size. ++ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. ++ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), ++ sockaddr_storage_pad2size = (sockaddr_storage_maxsize - ++ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) ++}; ++ ++struct sockaddr_storage_emulation ++{ ++ short ss_family; ++ char __ss_pad1[sockaddr_storage_pad1size]; ++ __int64 __ss_align; ++ char __ss_pad2[sockaddr_storage_pad2size]; ++}; ++ ++struct in6_addr_emulation ++{ ++ union ++ { ++ u_char Byte[16]; ++ u_short Word[8]; ++ } u; ++}; ++ ++#if !defined(s6_addr) ++# define _S6_un u ++# define _S6_u8 Byte ++# define s6_addr _S6_un._S6_u8 ++#endif // !defined(s6_addr) ++ ++struct sockaddr_in6_emulation ++{ ++ short sin6_family; ++ u_short sin6_port; ++ u_long sin6_flowinfo; ++ in6_addr_emulation sin6_addr; ++ u_long sin6_scope_id; ++}; ++ ++struct ipv6_mreq_emulation ++{ ++ in6_addr_emulation ipv6mr_multiaddr; ++ unsigned int ipv6mr_interface; ++}; ++ ++struct addrinfo_emulation ++{ ++ int ai_flags; ++ int ai_family; ++ int ai_socktype; ++ int ai_protocol; ++ size_t ai_addrlen; ++ char* ai_canonname; ++ sockaddr* ai_addr; ++ addrinfo_emulation* ai_next; ++}; ++ ++#if !defined(AI_PASSIVE) ++# define AI_PASSIVE 0x1 ++#endif ++ ++#if !defined(AI_CANONNAME) ++# define AI_CANONNAME 0x2 ++#endif ++ ++#if !defined(AI_NUMERICHOST) ++# define AI_NUMERICHOST 0x4 ++#endif ++ ++#if !defined(EAI_AGAIN) ++# define EAI_AGAIN WSATRY_AGAIN ++#endif ++ ++#if !defined(EAI_BADFLAGS) ++# define EAI_BADFLAGS WSAEINVAL ++#endif ++ ++#if !defined(EAI_FAIL) ++# define EAI_FAIL WSANO_RECOVERY ++#endif ++ ++#if !defined(EAI_FAMILY) ++# define EAI_FAMILY WSAEAFNOSUPPORT ++#endif ++ ++#if !defined(EAI_MEMORY) ++# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY ++#endif ++ ++#if !defined(EAI_NODATA) ++# define EAI_NODATA WSANO_DATA ++#endif ++ ++#if !defined(EAI_NONAME) ++# define EAI_NONAME WSAHOST_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SERVICE) ++# define EAI_SERVICE WSATYPE_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SOCKTYPE) ++# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT ++#endif ++ ++#if !defined(NI_NOFQDN) ++# define NI_NOFQDN 0x01 ++#endif ++ ++#if !defined(NI_NUMERICHOST) ++# define NI_NUMERICHOST 0x02 ++#endif ++ ++#if !defined(NI_NAMEREQD) ++# define NI_NAMEREQD 0x04 ++#endif ++ ++#if !defined(NI_NUMERICSERV) ++# define NI_NUMERICSERV 0x08 ++#endif ++ ++#if !defined(NI_DGRAM) ++# define NI_DGRAM 0x10 ++#endif ++ ++#if !defined(IPPROTO_IPV6) ++# define IPPROTO_IPV6 41 ++#endif ++ ++#if !defined(IPV6_UNICAST_HOPS) ++# define IPV6_UNICAST_HOPS 4 ++#endif ++ ++#if !defined(IPV6_MULTICAST_IF) ++# define IPV6_MULTICAST_IF 9 ++#endif ++ ++#if !defined(IPV6_MULTICAST_HOPS) ++# define IPV6_MULTICAST_HOPS 10 ++#endif ++ ++#if !defined(IPV6_MULTICAST_LOOP) ++# define IPV6_MULTICAST_LOOP 11 ++#endif ++ ++#if !defined(IPV6_JOIN_GROUP) ++# define IPV6_JOIN_GROUP 12 ++#endif ++ ++#if !defined(IPV6_LEAVE_GROUP) ++# define IPV6_LEAVE_GROUP 13 ++#endif ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. ++#if !defined(IPV6_V6ONLY) ++# define IPV6_V6ONLY 27 ++#endif ++ ++// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. ++#if !defined(IPPROTO_ICMPV6) ++# define IPPROTO_ICMPV6 58 ++#endif ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP +diff --git a/ip-address/include/std/net/detail/pop_options.hpp b/ip-address/include/std/net/detail/pop_options.hpp +new file mode 100644 +index 0000000..8aa375e +--- /dev/null ++++ b/ip-address/include/std/net/detail/pop_options.hpp +@@ -0,0 +1,98 @@ ++// ++// detail/pop_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (pop) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if defined(STDNET_OBJC_WORKAROUND) ++# undef Protocol ++# undef id ++# undef STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option pop ++# pragma nopushoptwarn ++# pragma nopackwarning ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (pop) ++# pragma pack (pop) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/push_options.hpp b/ip-address/include/std/net/detail/push_options.hpp +new file mode 100644 +index 0000000..ec64373 +--- /dev/null ++++ b/ip-address/include/std/net/detail/push_options.hpp +@@ -0,0 +1,127 @@ ++// ++// detail/push_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (push, 8) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if !defined(STDNET_DISABLE_OBJC_WORKAROUND) ++# if !defined(Protocol) && !defined(id) ++# define Protocol cpp_Protocol ++# define id cpp_id ++# define STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- ++# pragma nopushoptwarn ++# pragma nopackwarning ++# if !defined(__MT__) ++# error Multithreaded RTL must be selected. ++# endif // !defined(__MT__) ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (disable:4103) ++# pragma warning (push) ++# pragma warning (disable:4127) ++# pragma warning (disable:4180) ++# pragma warning (disable:4244) ++# pragma warning (disable:4355) ++# pragma warning (disable:4512) ++# pragma warning (disable:4675) ++# if defined(_M_IX86) && defined(_Wp64) ++// The /Wp64 option is broken. If you want to check 64 bit portability, use a ++// 64 bit compiler! ++# pragma warning (disable:4311) ++# pragma warning (disable:4312) ++# endif // defined(_M_IX86) && defined(_Wp64) ++# pragma pack (push, 8) ++// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler ++// has a tendency to incorrectly optimise away some calls to member template ++// functions, even though those functions contain code that should not be ++// optimised away! Therefore we will always disable this optimisation option ++// for the MSVC6 compiler. ++# if (_MSC_VER < 1300) ++# pragma optimize ("g", off) ++# endif ++# if !defined(_MT) ++# error Multithreaded RTL must be selected. ++# endif // !defined(_MT) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/socket_ops.hpp b/ip-address/include/std/net/detail/socket_ops.hpp +new file mode 100644 +index 0000000..02cb8a4 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_ops.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/socket_ops.hpp ++// ~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_HPP ++#define STDNET_DETAIL_SOCKET_OPS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#include ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++STDNET_DECL const char* inet_ntop(int af, const void* src, char* dest, ++ size_t length, unsigned long scope_id, std::error_code& ec); ++ ++STDNET_DECL int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec); ++ ++STDNET_DECL u_long_type network_to_host_long(u_long_type value); ++ ++STDNET_DECL u_long_type host_to_network_long(u_long_type value); ++ ++STDNET_DECL u_short_type network_to_host_short(u_short_type value); ++ ++STDNET_DECL u_short_type host_to_network_short(u_short_type value); ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/socket_ops.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_HPP +diff --git a/ip-address/include/std/net/detail/socket_types.hpp b/ip-address/include/std/net/detail/socket_types.hpp +new file mode 100644 +index 0000000..ee35521 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_types.hpp +@@ -0,0 +1,186 @@ ++// ++// detail/socket_types.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_TYPES_HPP ++#define STDNET_DETAIL_SOCKET_TYPES_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# error WinSock.h has already been included ++# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# if defined(__BORLANDC__) ++# include // Needed for __errno ++# if !defined(_WSPIAPI_H_) ++# define _WSPIAPI_H_ ++# define STDNET_WSPIAPI_H_DEFINED ++# endif // !defined(_WSPIAPI_H_) ++# endif // defined(__BORLANDC__) ++# include ++# include ++# include ++# if defined(STDNET_WSPIAPI_H_DEFINED) ++# undef _WSPIAPI_H_ ++# undef STDNET_WSPIAPI_H_DEFINED ++# endif // defined(STDNET_WSPIAPI_H_DEFINED) ++# if !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# if defined(UNDER_CE) ++# pragma comment(lib, "ws2.lib") ++# elif defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma comment(lib, "ws2_32.lib") ++# pragma comment(lib, "mswsock.lib") ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# endif // !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# include "std/net/detail/old_win_sdk_compat.hpp" ++#else ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# if defined(__hpux) ++# include ++# endif ++# if !defined(__hpux) || defined(__SELECT) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if defined(__sun) ++# include ++# include ++# endif ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++typedef SOCKET socket_type; ++const SOCKET invalid_socket = INVALID_SOCKET; ++const int socket_error_retval = SOCKET_ERROR; ++const int max_addr_v4_str_len = 256; ++const int max_addr_v6_str_len = 256; ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++typedef ip_mreq in4_mreq_type; ++typedef sockaddr_in sockaddr_in4_type; ++# if defined(STDNET_HAS_OLD_WIN_SDK) ++typedef in6_addr_emulation in6_addr_type; ++typedef ipv6_mreq_emulation in6_mreq_type; ++typedef sockaddr_in6_emulation sockaddr_in6_type; ++typedef sockaddr_storage_emulation sockaddr_storage_type; ++typedef addrinfo_emulation addrinfo_type; ++# else ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef addrinfo addrinfo_type; ++# endif ++typedef unsigned long ioctl_arg_type; ++typedef u_long u_long_type; ++typedef u_short u_short_type; ++typedef int signed_size_type; ++const int shutdown_receive = SD_RECEIVE; ++const int shutdown_send = SD_SEND; ++const int shutdown_both = SD_BOTH; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = 0; // Not supported on Windows. ++# if defined (_WIN32_WINNT) ++const int max_iov_len = 64; ++# else ++const int max_iov_len = 16; ++# endif ++#else ++typedef int socket_type; ++const int invalid_socket = -1; ++const int socket_error_retval = -1; ++const int max_addr_v4_str_len = INET_ADDRSTRLEN; ++#if defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; ++#else // defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = 256; ++#endif // defined(INET6_ADDRSTRLEN) ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++# if defined(__hpux) ++// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. ++struct in4_mreq_type ++{ ++ struct in_addr imr_multiaddr; ++ struct in_addr imr_interface; ++}; ++# else ++typedef ip_mreq in4_mreq_type; ++# endif ++typedef sockaddr_in sockaddr_in4_type; ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef sockaddr_un sockaddr_un_type; ++typedef addrinfo addrinfo_type; ++typedef int ioctl_arg_type; ++typedef uint32_t u_long_type; ++typedef uint16_t u_short_type; ++#if defined(STDNET_HAS_SSIZE_T) ++typedef ssize_t signed_size_type; ++#else // defined(STDNET_HAS_SSIZE_T) ++typedef int signed_size_type; ++#endif // defined(STDNET_HAS_SSIZE_T) ++const int shutdown_receive = SHUT_RD; ++const int shutdown_send = SHUT_WR; ++const int shutdown_both = SHUT_RDWR; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = MSG_EOR; ++# if defined(IOV_MAX) ++const int max_iov_len = IOV_MAX; ++# else ++// POSIX platforms are not required to define IOV_MAX. ++const int max_iov_len = 16; ++# endif ++#endif ++const int custom_socket_option_level = 0xA5100000; ++const int enable_connection_aborted_option = 1; ++const int always_fail_option = 2; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_TYPES_HPP +diff --git a/ip-address/include/std/net/detail/system_errors.hpp b/ip-address/include/std/net/detail/system_errors.hpp +new file mode 100644 +index 0000000..4aa5c44 +--- /dev/null ++++ b/ip-address/include/std/net/detail/system_errors.hpp +@@ -0,0 +1,221 @@ ++// ++// system_errors.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SYSTEM_ERRORS_HPP ++#define STDNET_DETAIL_SYSTEM_ERRORS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# include ++#else ++# include ++#endif ++ ++#if defined(GENERATING_DOCUMENTATION) ++/// INTERNAL ONLY. ++# define STDNET_NATIVE_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_SOCKET_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_NETDB_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_GETADDRINFO_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) implementation_defined ++#elif defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) WSA ## e ++# define STDNET_NETDB_ERROR(e) WSA ## e ++# define STDNET_GETADDRINFO_ERROR(e) WSA ## e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_win ++#else ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) e ++# define STDNET_NETDB_ERROR(e) e ++# define STDNET_GETADDRINFO_ERROR(e) e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_posix ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++enum system_errors ++{ ++ /// Permission denied. ++ access_denied = STDNET_SOCKET_ERROR(EACCES), ++ ++ /// Address family not supported by protocol. ++ address_family_not_supported = STDNET_SOCKET_ERROR(EAFNOSUPPORT), ++ ++ /// Address already in use. ++ address_in_use = STDNET_SOCKET_ERROR(EADDRINUSE), ++ ++ /// Transport endpoint is already connected. ++ already_connected = STDNET_SOCKET_ERROR(EISCONN), ++ ++ /// Operation already in progress. ++ already_started = STDNET_SOCKET_ERROR(EALREADY), ++ ++ /// Broken pipe. ++ broken_pipe = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_BROKEN_PIPE), ++ STDNET_NATIVE_ERROR(EPIPE)), ++ ++ /// A connection has been aborted. ++ connection_aborted = STDNET_SOCKET_ERROR(ECONNABORTED), ++ ++ /// Connection refused. ++ connection_refused = STDNET_SOCKET_ERROR(ECONNREFUSED), ++ ++ /// Connection reset by peer. ++ connection_reset = STDNET_SOCKET_ERROR(ECONNRESET), ++ ++ /// Bad file descriptor. ++ bad_descriptor = STDNET_SOCKET_ERROR(EBADF), ++ ++ /// Bad address. ++ fault = STDNET_SOCKET_ERROR(EFAULT), ++ ++ /// No route to host. ++ host_unreachable = STDNET_SOCKET_ERROR(EHOSTUNREACH), ++ ++ /// Operation now in progress. ++ in_progress = STDNET_SOCKET_ERROR(EINPROGRESS), ++ ++ /// Interrupted system call. ++ interrupted = STDNET_SOCKET_ERROR(EINTR), ++ ++ /// Invalid argument. ++ invalid_argument = STDNET_SOCKET_ERROR(EINVAL), ++ ++ /// Message too long. ++ message_size = STDNET_SOCKET_ERROR(EMSGSIZE), ++ ++ /// The name was too long. ++ name_too_long = STDNET_SOCKET_ERROR(ENAMETOOLONG), ++ ++ /// Network is down. ++ network_down = STDNET_SOCKET_ERROR(ENETDOWN), ++ ++ /// Network dropped connection on reset. ++ network_reset = STDNET_SOCKET_ERROR(ENETRESET), ++ ++ /// Network is unreachable. ++ network_unreachable = STDNET_SOCKET_ERROR(ENETUNREACH), ++ ++ /// Too many open files. ++ no_descriptors = STDNET_SOCKET_ERROR(EMFILE), ++ ++ /// No buffer space available. ++ no_buffer_space = STDNET_SOCKET_ERROR(ENOBUFS), ++ ++ /// Cannot allocate memory. ++ no_memory = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OUTOFMEMORY), ++ STDNET_NATIVE_ERROR(ENOMEM)), ++ ++ /// Operation not permitted. ++ no_permission = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_ACCESS_DENIED), ++ STDNET_NATIVE_ERROR(EPERM)), ++ ++ /// Protocol not available. ++ no_protocol_option = STDNET_SOCKET_ERROR(ENOPROTOOPT), ++ ++ /// Transport endpoint is not connected. ++ not_connected = STDNET_SOCKET_ERROR(ENOTCONN), ++ ++ /// Socket operation on non-socket. ++ not_socket = STDNET_SOCKET_ERROR(ENOTSOCK), ++ ++ /// Operation cancelled. ++ operation_aborted = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OPERATION_ABORTED), ++ STDNET_NATIVE_ERROR(ECANCELED)), ++ ++ /// Operation not supported. ++ operation_not_supported = STDNET_SOCKET_ERROR(EOPNOTSUPP), ++ ++ /// Cannot send after transport endpoint shutdown. ++ shut_down = STDNET_SOCKET_ERROR(ESHUTDOWN), ++ ++ /// Connection timed out. ++ timed_out = STDNET_SOCKET_ERROR(ETIMEDOUT), ++ ++ /// Resource temporarily unavailable. ++ try_again = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_RETRY), ++ STDNET_NATIVE_ERROR(EAGAIN)), ++ ++ /// The socket is marked non-blocking and the requested operation would block. ++ would_block = STDNET_SOCKET_ERROR(EWOULDBLOCK) ++}; ++ ++} // namespace syserrc ++ ++/// Returns the error category used for the system errors. ++extern STDNET_DECL const std::error_category& system_category(); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++namespace std { ++ ++template<> struct is_error_code_enum< ++ std::experimental::net::detail::syserrc::system_errors> ++{ ++ static const bool value = true; ++}; ++ ++} // namespace std ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++inline std::error_code make_error_code(system_errors e) ++{ ++ return std::error_code(static_cast(e), ++ std::experimental::net::detail::system_category()); ++} ++ ++} // namespace syserrc ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#undef STDNET_NATIVE_ERROR ++#undef STDNET_SOCKET_ERROR ++#undef STDNET_NETDB_ERROR ++#undef STDNET_GETADDRINFO_ERROR ++#undef STDNET_WIN_OR_POSIX ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/system_errors.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SYSTEM_ERRORS_HPP +diff --git a/ip-address/include/std/net/detail/throw_error.hpp b/ip-address/include/std/net/detail/throw_error.hpp +new file mode 100644 +index 0000000..4067cb7 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_error.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/throw_error.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_ERROR_HPP ++#define STDNET_DETAIL_THROW_ERROR_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++STDNET_DECL void do_throw_error(const std::error_code& err); ++ ++STDNET_DECL void do_throw_error(const std::error_code& err, ++ const char* location); ++ ++inline void throw_error(const std::error_code& err) ++{ ++ if (err) ++ do_throw_error(err); ++} ++ ++inline void throw_error(const std::error_code& err, ++ const char* location) ++{ ++ if (err) ++ do_throw_error(err, location); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/throw_error.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_THROW_ERROR_HPP +diff --git a/ip-address/include/std/net/detail/throw_exception.hpp b/ip-address/include/std/net/detail/throw_exception.hpp +new file mode 100644 +index 0000000..0903df1 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_exception.hpp +@@ -0,0 +1,45 @@ ++// ++// detail/throw_exception.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_EXCEPTION_HPP ++#define STDNET_DETAIL_THROW_EXCEPTION_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++// Declare the throw_exception function for all targets. ++template ++void throw_exception(const Exception& e); ++ ++// Only define the throw_exception function when exceptions are enabled. ++// Otherwise, it is up to the application to provide a definition of this ++// function. ++# if !defined(STDNET_NO_EXCEPTIONS) ++template ++void throw_exception(const Exception& e) ++{ ++ throw e; ++} ++# endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#endif // STDNET_DETAIL_THROW_EXCEPTION_HPP +diff --git a/ip-address/include/std/net/detail/winsock_init.hpp b/ip-address/include/std/net/detail/winsock_init.hpp +new file mode 100644 +index 0000000..fc008de +--- /dev/null ++++ b/ip-address/include/std/net/detail/winsock_init.hpp +@@ -0,0 +1,94 @@ ++// ++// detail/winsock_init.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_WINSOCK_INIT_HPP ++#define STDNET_DETAIL_WINSOCK_INIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class winsock_init_base ++{ ++protected: ++ // Structure to track result of initialisation and number of uses. POD is used ++ // to ensure that the values are zero-initialised prior to any code being run. ++ struct data ++ { ++ long init_count_; ++ long result_; ++ }; ++ ++ STDNET_DECL static void startup(data& d, ++ unsigned char major, unsigned char minor); ++ ++ STDNET_DECL static void cleanup(data& d); ++ ++ STDNET_DECL static void throw_on_error(data& d); ++}; ++ ++template ++class winsock_init : private winsock_init_base ++{ ++public: ++ winsock_init(bool allow_throw = true) ++ { ++ startup(data_, Major, Minor); ++ if (allow_throw) ++ throw_on_error(data_); ++ } ++ ++ winsock_init(const winsock_init&) ++ { ++ startup(data_, Major, Minor); ++ throw_on_error(data_); ++ } ++ ++ ~winsock_init() ++ { ++ cleanup(data_); ++ } ++ ++private: ++ static data data_; ++}; ++ ++template ++winsock_init_base::data winsock_init::data_; ++ ++// Static variable to ensure that winsock is initialised before main, and ++// therefore before any other threads can get started. ++static const winsock_init<>& winsock_init_instance = winsock_init<>(false); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/winsock_init.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_WINSOCK_INIT_HPP +diff --git a/ip-address/include/std/net/ip/address.hpp b/ip-address/include/std/net/ip/address.hpp +new file mode 100644 +index 0000000..8a5e75a +--- /dev/null ++++ b/ip-address/include/std/net/ip/address.hpp +@@ -0,0 +1,328 @@ ++// ++// ip/address.hpp ++// ~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_HPP ++#define STDNET_IP_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++namespace detail { ++ ++template ++struct is_convertible_to_address_1 : false_type {}; ++ ++template ++struct is_convertible_to_address_1(declval()))>::value>::type> : true_type {}; ++ ++template ++struct is_convertible_to_address : is_convertible_to_address_1 {}; ++ ++template <> ++struct is_convertible_to_address
: false_type {}; ++ ++} // namespace detail ++ ++//template <> struct is_convertible_to_address
: false_type {}; ++ ++/// Implements version-independent IP addresses. ++/** ++ * The ip::address class provides the ability to use either IP version 4 or ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address ++{ ++public: ++ /// Default constructor. ++ STDNET_CONSTEXPR address() STDNET_NOEXCEPT ++ : type_(invalid), ++ ipv4_address_(), ++ ipv6_address_() ++ { ++ } ++ ++ /// Construct from another address type. ++ template ::value>::type> ++ STDNET_CONSTEXPR address(const T& t) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address(T&&... t); ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit address(T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ explicit address(const T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ address(T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address(const address& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address(address&& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address& operator=(const address& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address& operator=(address&& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get whether the address is an IP version 4 address. ++ STDNET_CONSTEXPR bool is_v4() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv4; ++ } ++ ++ /// Get whether the address is an IP version 6 address. ++ STDNET_CONSTEXPR bool is_v6() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv6; ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_loopback() : ++ (type_ == ipv6) ? ipv6_address_.is_loopback() : false; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_unspecified() : ++ (type_ == ipv6) ? ipv6_address_.is_unspecified() : false; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_multicast() : ++ (type_ == ipv6) ? ipv6_address_.is_multicast() : false; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ != a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ return true; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ < a2.type_) ++ return true; ++ if (a1.type_ > a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ < a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv6_address_ < a2.ipv6_address_; ++ return false; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++private: ++ friend class address_v4; ++ friend class address_v6; ++ ++ // The type of the address. ++ enum address_type { invalid, ipv4, ipv6 } type_; ++ ++ // The underlying IPv4 address. ++ address_v4 ipv4_address_; ++ ++ // The underlying IPv6 address. ++ address_v6 ipv6_address_; ++ ++ // Helper constructor for address_cast. ++ STDNET_CONSTEXPR address(address_type type, ++ const address_v4& v4, const address_v6& v6) ++ : type_(type), ++ ipv4_address_(v4), ++ ipv6_address_(v6) ++ { ++ } ++ ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++ template friend STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++}; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#include "std/net/ip/address_cast.hpp" ++ ++#endif // STDNET_IP_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/address_cast.hpp b/ip-address/include/std/net/ip/address_cast.hpp +new file mode 100644 +index 0000000..dae3d02 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_cast.hpp +@@ -0,0 +1,106 @@ ++// ++// ip/address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_CAST_HPP ++#define STDNET_IP_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Cast a version-independent address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast a version-independent address to an IPv4 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv4 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv4) ++ ? throw bad_address_cast() ++ : addr.ipv4_address_; ++} ++ ++/// Cast a version-independent address to an IPv6 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv6 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv6) ++ ? throw bad_address_cast() ++ : addr.ipv6_address_; ++} ++ ++/// Cast an IPv4 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv4, addr, address_v6()); ++} ++ ++/// Cast an IPv4 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast an IPv6 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv6, address_v4(), addr); ++} ++ ++/// Cast an IPv6 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/address_v4.hpp b/ip-address/include/std/net/ip/address_v4.hpp +new file mode 100644 +index 0000000..a7b9234 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v4.hpp +@@ -0,0 +1,376 @@ ++// ++// ip/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V4_HPP ++#define STDNET_IP_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++ ++/// Implements IP version 4 style addresses. ++/** ++ * The ip::address_v4 class provides the ability to use and manipulate IP ++ * version 4 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v4 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type(unsigned char a = 0, ++ unsigned char b = 0, unsigned char c = 0, unsigned char d = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v4() STDNET_NOEXCEPT ++ : bytes_(0, 0, 0, 0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v4(const bytes_type& bytes) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF) ++ ? throw std::out_of_range("address_v4 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v4(T&&... t) ++ : address_v4(make_address_v4(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v4(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v4(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v4(const address_v4& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v4(address_v4&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v4& operator=(const address_v4& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v4& operator=(address_v4&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as an unsigned long in host byte order ++ STDNET_CONSTEXPR unsigned long to_ulong() const STDNET_NOEXCEPT ++ { ++ return (static_cast(bytes_[0]) << 24) ++ | (static_cast(bytes_[1]) << 16) ++ | (static_cast(bytes_[2]) << 8) ++ | static_cast(bytes_[3]); ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xFF000000) == 0x7F000000; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return to_ulong() == 0; ++ } ++ ++ /// Determine whether the address is a class A address. ++ STDNET_CONSTEXPR bool is_class_a() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0x80000000) == 0; ++ } ++ ++ /// Determine whether the address is a class B address. ++ STDNET_CONSTEXPR bool is_class_b() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xC0000000) == 0x80000000; ++ } ++ ++ /// Determine whether the address is a class C address. ++ STDNET_CONSTEXPR bool is_class_c() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xE0000000) == 0xC0000000; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xF0000000) == 0xE0000000; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() < a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() > a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() <= a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() >= a2.to_ulong(); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v4 any() STDNET_NOEXCEPT ++ { ++ return address_v4(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v4 loopback() STDNET_NOEXCEPT ++ { ++ return address_v4(0x7F000001); ++ } ++ ++ /// Obtain an address object that represents the broadcast address. ++ static STDNET_CONSTEXPR address_v4 broadcast() STDNET_NOEXCEPT ++ { ++ return address_v4(0xFFFFFFFF); ++ } ++ ++ /// Obtain an address object that represents the broadcast address that ++ /// corresponds to the specified address and netmask. ++ static STDNET_CONSTEXPR address_v4 broadcast(const address_v4& addr, ++ const address_v4& mask) STDNET_NOEXCEPT ++ { ++ return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); ++ } ++ ++private: ++ // The underlying IPv4 address. ++ bytes_type bytes_; ++}; ++ ++/// Construct an address_v4 from raw bytes. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::bytes_type& bytes) ++{ ++ return bytes; ++} ++ ++/// Construct an address_v4 from a unsigned long in host byte order. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long addr) ++{ ++ return ++#if ULONG_MAX > 0xFFFFFFFF ++ (addr > 0xFFFFFFFF) ++ ? throw std::out_of_range("address_v4 from unsigned long") : ++#endif // ULONG_MAX > 0xFFFFFFFF ++ address_v4::bytes_type((addr >> 24) & 0xFF, ++ (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF); ++} ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++ ++/// The IPv4 unspecified address. ++STDNET_CONSTEXPR address_v4 any_v4(0); ++ ++/// The IPv4 loopback address. ++STDNET_CONSTEXPR address_v4 loopback_v4(0x7F000001); ++ ++/// The IPv4 broadcast address. ++STDNET_CONSTEXPR address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#else // defined(STDNET_HAS_CONSTEXPR) ++ ++static const address_v4 any_v4(0); ++static const address_v4 loopback_v4(0x7F000001); ++static const address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#endif // defined(STDNET_HAS_CONSTEXPR) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v4 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v4.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v4.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/address_v6.hpp b/ip-address/include/std/net/ip/address_v6.hpp +new file mode 100644 +index 0000000..3c4f440 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v6.hpp +@@ -0,0 +1,440 @@ ++// ++// ip/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V6_HPP ++#define STDNET_IP_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++class address_v4; ++ ++/// Implements IP version 6 style addresses. ++/** ++ * The ip::address_v6 class provides the ability to use and manipulate IP ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v6 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type( ++ unsigned char a = 0, unsigned char b = 0, ++ unsigned char c = 0, unsigned char d = 0, ++ unsigned char e = 0, unsigned char f = 0, ++ unsigned char g = 0, unsigned char h = 0, ++ unsigned char i = 0, unsigned char j = 0, ++ unsigned char k = 0, unsigned char l = 0, ++ unsigned char m = 0, unsigned char n = 0, ++ unsigned char o = 0, unsigned char p = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d, e, f, g, h, i, h, k, l, m, n, o, p}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ (*this)[4] = e, (*this)[5] = f, (*this)[6] = g, (*this)[7] = h; ++ (*this)[8] = i, (*this)[9] = j, (*this)[10] = k, (*this)[11] = l; ++ (*this)[12] = m, (*this)[13] = n, (*this)[14] = o, (*this)[15] = p; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v6() STDNET_NOEXCEPT ++ : bytes_(0), ++ scope_id_(0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v6(const bytes_type& bytes, unsigned long scope = 0) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF ++ || bytes[4] > 0xFF || bytes[5] > 0xFF || bytes[6] > 0xFF || bytes[7] > 0xFF ++ || bytes[8] > 0xFF || bytes[9] > 0xFF || bytes[10] > 0xFF || bytes[11] > 0xFF ++ || bytes[12] > 0xFF || bytes[13] > 0xFF || bytes[14] > 0xFF || bytes[15] > 0xFF) ++ ? throw std::out_of_range("address_v6 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes), ++ scope_id_(scope) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v6(T&&... t) ++ : address_v6(make_address_v6(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v6(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v6(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v6(const address_v6& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v6(address_v6&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v6& operator=(const address_v6& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v6& operator=(address_v6&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// The scope ID of the address. ++ /** ++ * Returns the scope ID associated with the IPv6 address. ++ */ ++ STDNET_CONSTEXPR unsigned long scope_id() const STDNET_NOEXCEPT ++ { ++ return scope_id_; ++ } ++ ++ /// The scope ID of the address. ++ /** ++ * Modifies the scope ID associated with the IPv6 address. ++ */ ++ void scope_id(unsigned long id) STDNET_NOEXCEPT ++ { ++ scope_id_ = id; ++ } ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 1)); ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 0)); ++ } ++ ++ /// Determine whether the address is link local. ++ STDNET_CONSTEXPR bool is_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0x80)); ++ } ++ ++ /// Determine whether the address is site local. ++ STDNET_CONSTEXPR bool is_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0xc0)); ++ } ++ ++ /// Determine whether the address is a mapped IPv4 address. ++ STDNET_CONSTEXPR bool is_v4_mapped() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0xff) && (bytes_[11] == 0xff)); ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (bytes_[0] == 0xff); ++ } ++ ++ /// Determine whether the address is a global multicast address. ++ STDNET_CONSTEXPR bool is_multicast_global() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x0e)); ++ } ++ ++ /// Determine whether the address is a link-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x02)); ++ } ++ ++ /// Determine whether the address is a node-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_node_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x01)); ++ } ++ ++ /// Determine whether the address is a org-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_org_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x08)); ++ } ++ ++ /// Determine whether the address is a site-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x05)); ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_ && a1.scope_id_ == a2.scope_id_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ if (a1.bytes_ < a2.bytes_) ++ return true; ++ if (a1.bytes_ > a2.bytes_) ++ return false; ++ return a1.scope_id_ < a2.scope_id_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v6 any() STDNET_NOEXCEPT ++ { ++ return address_v6(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v6 loopback() STDNET_NOEXCEPT ++ { ++ return bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); ++ } ++ ++private: ++ friend STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6&); ++ ++ // The underlying IPv6 address. ++ bytes_type bytes_; ++ ++ // The scope ID associated with the address. ++ unsigned long scope_id_; ++}; ++ ++/// Construct an address_v6 from raw bytes. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ const address_v6::bytes_type& bytes, unsigned long scope_id = 0) ++{ ++ return address_v6(bytes, scope_id); ++} ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an IPv4-mapped address_v6 from an IPv4 address. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ v4_mapped_t, const address_v4& addr) STDNET_NOEXCEPT ++{ ++ return address_v6::bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, ++ static_cast(addr.to_bytes())[0], ++ static_cast(addr.to_bytes())[1], ++ static_cast(addr.to_bytes())[2], ++ static_cast(addr.to_bytes())[3]); ++} ++ ++/// Create an address_v4 from an IPv4-mapped address_v6. ++inline STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6& addr) ++{ ++ return !addr.is_v4_mapped() ? throw bad_address_cast() : ++ address_v4::bytes_type(addr.bytes_[12], addr.bytes_[13], ++ addr.bytes_[14], addr.bytes_[15]); ++} ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v6 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v6.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v6.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/bad_address_cast.hpp b/ip-address/include/std/net/ip/bad_address_cast.hpp +new file mode 100644 +index 0000000..bc330c2 +--- /dev/null ++++ b/ip-address/include/std/net/ip/bad_address_cast.hpp +@@ -0,0 +1,46 @@ ++// ++// ip/bad_address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_BAD_ADDRESS_CAST_HPP ++#define STDNET_IP_BAD_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Exception thrown on a failed address_cast. ++class bad_address_cast ++ : public bad_cast ++{ ++public: ++ virtual const char* what() const STDNET_NOEXCEPT ++ { ++ return "bad address cast"; ++ } ++}; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_BAD_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/fwd.hpp b/ip-address/include/std/net/ip/fwd.hpp +new file mode 100644 +index 0000000..2c8f929 +--- /dev/null ++++ b/ip-address/include/std/net/ip/fwd.hpp +@@ -0,0 +1,149 @@ ++// ++// ip/fwd.hpp ++// ~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_FWD_HPP ++#define STDNET_IP_FWD_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++struct v4_mapped_t { STDNET_CONSTEXPR v4_mapped_t() {} }; ++STDNET_CONSTEXPR v4_mapped_t v4_mapped; ++#else // !defined(STDNET_HAS_CONSTEXPR) ++enum v4_mapped_t { v4_mapped }; ++#endif // !defined(STDNET_HAS_CONSTEXPR) ++ ++class address; ++class address_v4; ++class address_v6; ++ ++// address comparisons: ++bool operator==(const address&, const address&) STDNET_NOEXCEPT; ++bool operator!=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator< (const address&, const address&) STDNET_NOEXCEPT; ++bool operator> (const address&, const address&) STDNET_NOEXCEPT; ++bool operator<=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator>=(const address&, const address&) STDNET_NOEXCEPT; ++ ++// address creation: ++address make_address(const char*); ++address make_address(const char*, std::error_code&) STDNET_NOEXCEPT; ++address make_address(const std::string&); ++address make_address(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 comparisons: ++bool operator==(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator!=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator< (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator> (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator<=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator>=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++ ++// address_v4 creation: ++//STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::octets&); ++STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long); ++STDNET_CONSTEXPR address_v4 make_address_v4(v4_mapped_t, const address_v6&); ++address_v4 make_address_v4(const char*); ++address_v4 make_address_v4(const char*, error_code&) STDNET_NOEXCEPT; ++address_v4 make_address_v4(const std::string&); ++address_v4 make_address_v4(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v4&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 comparisons: ++bool operator==(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator!=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator< (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator> (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator<=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator>=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++ ++// address_v6 creation: ++//STDNET_CONSTEXPR address_v6 make_address_v6(const address_v6::octets&, unsigned long = 0); ++STDNET_CONSTEXPR address_v6 make_address_v6(v4_mapped_t, const address_v4&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const char*); ++address_v6 make_address_v6(const char*, error_code&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const std::string&); ++address_v6 make_address_v6(const std::string&, error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v6&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++class bad_address_cast; ++ ++// address conversion: ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_FWD_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.hpp b/ip-address/include/std/net/ip/impl/address.hpp +new file mode 100644 +index 0000000..82dc09c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.hpp +@@ -0,0 +1,74 @@ ++// ++// ip/impl/address.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_HPP ++#define STDNET_IP_IMPL_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/ip/address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++inline STDNET_CONSTEXPR address::address(const T& t) STDNET_NOEXCEPT ++ : address(address_cast
(t)) ++{ ++} ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++template ++inline STDNET_CONSTEXPR address::address(T&&... t) ++ : address(make_address(static_cast(t)...)) ++{ ++} ++ ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.ipp b/ip-address/include/std/net/ip/impl/address.ipp +new file mode 100644 +index 0000000..b74189c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.ipp +@@ -0,0 +1,91 @@ ++// ++// ip/impl/address.ipp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_IPP ++#define STDNET_IP_IMPL_ADDRESS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/ip/address.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address::to_string() const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(); ++ throw bad_address_cast(); ++} ++ ++std::string address::to_string(std::error_code& ec) const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(ec); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(ec); ++ throw bad_address_cast(); ++} ++ ++address make_address(const char* str) ++{ ++ std::error_code ec; ++ address addr = make_address(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6 ipv6_address = make_address_v6(str, ec); ++ if (!ec) ++ return ipv6_address; ++ ++ address_v4 ipv4_address = make_address_v4(str, ec); ++ if (!ec) ++ return ipv4_address; ++ ++ return address(); ++} ++ ++address make_address(const std::string& str) ++{ ++ return make_address(str.c_str()); ++} ++ ++address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.hpp b/ip-address/include/std/net/ip/impl/address_v4.hpp +new file mode 100644 +index 0000000..8544419 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_HPP ++#define STDNET_IP_IMPL_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.ipp b/ip-address/include/std/net/ip/impl/address_v4.ipp +new file mode 100644 +index 0000000..1ed99f7 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v4.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_IPP ++#define STDNET_IP_IMPL_ADDRESS_V4_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v4.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v4::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v4::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v4_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v4_str_len, 0, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str) ++{ ++ std::error_code ec; ++ address_v4 addr = make_address_v4(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v4::bytes_type bytes; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET, str, bytes.data(), 0, ec) <= 0) ++ return address_v4(); ++ return address_v4(bytes); ++} ++ ++address_v4 make_address_v4(const std::string& str) ++{ ++ return make_address_v4(str.c_str()); ++} ++ ++address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v4(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.hpp b/ip-address/include/std/net/ip/impl/address_v6.hpp +new file mode 100644 +index 0000000..1b3fd23 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_HPP ++#define STDNET_IP_IMPL_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.ipp b/ip-address/include/std/net/ip/impl/address_v6.ipp +new file mode 100644 +index 0000000..682160b +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v6.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_IPP ++#define STDNET_IP_IMPL_ADDRESS_V6_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v6::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v6::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v6_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET6, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v6_str_len, ++ scope_id_, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str) ++{ ++ std::error_code ec; ++ address_v6 addr = make_address_v6(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6::bytes_type bytes; ++ unsigned long scope_id = 0; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET6, str, bytes.data(), &scope_id, ec) <= 0) ++ return address_v6(); ++ return address_v6(bytes, scope_id); ++} ++ ++address_v6 make_address_v6(const std::string& str) ++{ ++ return make_address_v6(str.c_str()); ++} ++ ++address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v6(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_IPP +diff --git a/ip-address/include/std/net/literals.hpp b/ip-address/include/std/net/literals.hpp +new file mode 100644 +index 0000000..2f10279 +--- /dev/null ++++ b/ip-address/include/std/net/literals.hpp +@@ -0,0 +1,51 @@ ++// ++// literals.hpp ++// ~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_LITERALS_HPP ++#define STDNET_LITERALS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++inline namespace literals { ++inline namespace net_literals { ++ ++inline net::ip::address operator"" _ip(const char* str, std::size_t) ++{ ++ return net::ip::make_address(str); ++} ++ ++inline net::ip::address_v4 operator"" _ipv4(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v4(str); ++} ++ ++inline net::ip::address_v6 operator"" _ipv6(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v6(str); ++} ++ ++} // inline namespace net_literals ++} // inline namespace literals ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_LITERALS_HPP +diff --git a/ip_prefix.cc b/ip_prefix.cc +new file mode 100644 +index 0000000..871ee73 +--- /dev/null ++++ b/ip_prefix.cc +@@ -0,0 +1,124 @@ ++// ip_prefix.cc: IP_prefix class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++#include ++ ++ ++// Namespace aliases ++namespace ip = std::experimental::net::ip; ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++string IP_prefix::to_bitstring(unsigned short int byte) { ++ string result = "00000000"; ++ for (int i = 7; i >= 0; i--) { ++ if (byte > 0) { ++ if (byte % 2 == 0) { ++ result[i] = '0'; ++ } else { ++ result[i] = '1'; ++ } ++ byte /= 2; ++ } ++ } ++ return result; ++} // end to_bitstring() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++IP_prefix::IP_prefix(const string& str, bool bitstring) { ++ if (bitstring) { // str represents bits of an IPv4/IPv6 prefix ++ prefix = str; ++ } else { // str represents a valid IPv4/IPv6 prefix in the standard notation ++ // extract prefix ++ string pref = str.substr(0, str.find('/')); ++ // extract prefix length ++ int len = atoi(str.substr(str.find('/')+1).c_str()); ++ ++ // transform address part of the prefix into generic format ++ ip::address addr(pref); ++ ++ // transform generic format into bitstring format ++ string addr_bitstring; ++ if (addr.is_v4()) { // IPv4 ++ ip::address_v4 addr_v4(pref); ++ ip::address_v4::bytes_type addr_v4_bytes = addr_v4.to_bytes(); ++ for (ip::address_v4::bytes_type::iterator it = addr_v4_bytes.begin(); it != addr_v4_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } else if (addr.is_v6()){ // IPv6 ++ ip::address_v6 addr_v6(pref); ++ ip::address_v6::bytes_type addr_v6_bytes = addr_v6.to_bytes(); ++ for (ip::address_v6::bytes_type::iterator it = addr_v6_bytes.begin(); it != addr_v6_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++ } ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(unsigned addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix& IP_prefix::operator= (const IP_prefix& orig) { ++ // create a copy of class members ++ prefix = orig.get_prefix(); ++ // return the created object ++ return *this; ++} // end operator= () ++ ++ ++unsigned IP_prefix::get_prefix_unsigned() const { ++ // initialize auxiliary variables ++ unsigned prefix_uns = 0; ++ unsigned pow = 1; ++ ++ // iterate over all bits of an unsigned integer from right to left ++ for (int i = 31; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns; ++} // end get_prefix_unsigned(); +diff --git a/ip_prefix.h b/ip_prefix.h +new file mode 100644 +index 0000000..f21616f +--- /dev/null ++++ b/ip_prefix.h +@@ -0,0 +1,128 @@ ++// ip_prefix.h: header file for IP_prefix class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef IP_PREFIX_H ++#define IP_PREFIX_H ++ ++ ++#include ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of IPv4/IPv6 prefixes. ++ * ++ * IP prefixes are represented as bitstrings where the first character ++ * represents the MSB of an IP address. Prefix length is determined by the ++ * length of the bitstring. ++ */ ++class IP_prefix { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * String of bits representing the prefix. ++ * The first character represents the MSB of the prefix and the prefix ++ * length is given by the length of this string. ++ */ ++ string prefix; ++ ++ /* ++ * Static function for conversion of a single byte into a bitstring. ++ * @param byte Byte to be converted. ++ * @return Byte converted into bitstring. ++ */ ++ static string to_bitstring(unsigned short int byte); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * Constructs an empty object of the IP_prefix class ++ */ ++ inline IP_prefix() {}; ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given string ++ * representing either bits of an IPv4/IPv6 prefix (the length of the ++ * string being the lenght of the prefix) or a valid IPv4/IPv6 prefix in ++ * the standard notation. ++ * @param str String representing an IPv4/IPv6 prefix in a format ++ * determined by the bitsring parameter. ++ * @param bitstring str represents bits of an IPv4/IPv6 prefix (TRUE) ++ * or a valid IPv4/IPv6 prefix in the standard ++ * notation (FALSE). ++ */ ++ IP_prefix(const string& str, bool bitsring); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4 prefix ++ * represented by its address part (unsigned integer) and length ++ * (integer). ++ * @param addr Address part of the IPv4 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(unsigned addr, int len); ++ ++ /* ++ * Copy assignment. ++ * Constructs a new IP prefix object by asigning a copy of the original ++ * IP prefix object. ++ * @param orig Reference to the original IP prefix object. ++ * @return Reference to the new IP prefix object. ++ */ ++ IP_prefix& operator= (const IP_prefix& orig); ++ ++ /* ++ * Comparison operator. ++ * Compares the current IP prefix object with the given IP prefix object. ++ * @param rhs_prefix IP prefix object to be compared with the current ++ * IP prefix object. ++ * @return TRUE if IP prefixes are equal, ++ * FALSE otherwise. ++ */ ++ inline bool operator== (const IP_prefix& rhs_prefix) const { ++ return (prefix == rhs_prefix.get_prefix()); ++ } ++ ++ /* ++ * Get function for the prefix bitstring. ++ * @return Bitstring representing IPv4/IPv6 prefix. ++ */ ++ inline string get_prefix() const { ++ return prefix; ++ } // end get_prefix() ++ ++ /* ++ * Get function for the prefix in the form of an unsigned number. ++ * @return Unsingned numbre representing IPv4/IPv6 prefix. ++ */ ++ unsigned get_prefix_unsigned() const; ++ ++ /* ++ * Get function for the prefix length. ++ * @return Prefix length. ++ */ ++ inline int get_length() const { ++ return prefix.length(); ++ } // end get_prefix() ++}; ++ ++#endif +diff --git a/makefile b/makefile +old mode 100755 +new mode 100644 +index 773f4c1..2750d37 +--- a/makefile ++++ b/makefile +@@ -9,15 +9,16 @@ + ## See README file for details + + CC = g++ ++LIB = -I./ip-address/include + ##CFLAGS = -g -pg +-CFLAGS = -O2 ++CFLAGS = -O2 -std=c++11 $(LIB) + .cc.o: + ${CC} ${CFLAGS} -c $*.cc + + sbintree.o : stdinc.h dlist.h sbintree.h + dbintree.o : stdinc.h dlist.h dbintree.h + random_db.o : stdinc.h FilterList.h random_db.h +-custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ++custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ip_prefix.h trie.h filter_graph.h + dlist.o : stdinc.h dlist.h + redundant_filter_check.o : stdinc.h redundant_filter_check.h + ## nesting_filter_check.o : stdinc.h nesting_filter_check.h +@@ -29,8 +30,15 @@ PrefixList.o : stdinc.h PrefixList.h + FilterList.o : stdinc.h FilterList.h + TupleBST.o : stdinc.h dlist.h TupleBST.h + db_generator.o : stdinc.h random_db.h PortList.h FilterList.h custom_db.h ++ip_prefix.o : ip_prefix.h ++trie.o : trie.h ++flow_network.o : flow_network.h ++filter_graph.o : stdinc.h filter_graph.h + +-db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o +- ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o -o db_generator ++db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o ip_prefix.o trie.o flow_network.o filter_graph.o ++ ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o ip_prefix.o trie.o flow_network.o filter_graph.o -o db_generator + + all: db_generator ++ ++clean: ++ rm -rf *.o db_generator +diff --git a/sbintree.cc b/sbintree.cc +index d755099..cbd4410 100644 +--- a/sbintree.cc ++++ b/sbintree.cc +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew +diff --git a/sbintree.h b/sbintree.h +index b085696..9deca63 100644 +--- a/sbintree.h ++++ b/sbintree.h +@@ -43,6 +43,17 @@ class sbintree { + void scale_skew(float scale_factor); // scale branching and skew according to scaling factor + void print_skew(FILE*); // print average skew per level + void build_tree(dlist* Flist, struct filter filters[]); ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; + + #endif +diff --git a/stdinc.h b/stdinc.h +index f566e0f..a66dfd7 100644 +--- a/stdinc.h ++++ b/stdinc.h +@@ -24,7 +24,7 @@ inline double max(double x, double y) { return x > y ? x : y; } + inline int min(int x, int y) { return x < y ? x : y; } + inline double min(double x, double y) { return x < y ? x : y; } + inline int abs(int x) { return x < 0 ? -x : x; } +-inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } ++// inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } + + inline void warning(char* p) { fprintf(stderr,"Warning:%s \n",p); } + inline void fatal(char* string) {fprintf(stderr,"Fatal:%s\n",string); exit(1); } +@@ -69,6 +69,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; +diff --git a/trie.cc b/trie.cc +new file mode 100644 +index 0000000..12f15de +--- /dev/null ++++ b/trie.cc +@@ -0,0 +1,1190 @@ ++// trie.cc: trie class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "trie.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Auxiliary class definitions ++// **************************************************************************** ++ ++class trie_nodes_greater_than_prefixes { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the number of prefixes ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if (node2->prefixes < node1->prefixes) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++class trie_nodes_greater_than_weight { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the total weight of nodes' subtrees ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if ((node2->zero_weight + node2->one_weight) < ++ (node1->zero_weight + node1->one_weight)) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++trie_node* Trie::copy(const trie_node* node, int level) { ++ // create a pointer to the root of a new trie ++ trie_node* copy_root; ++ // copy the given subtree ++ if (node != NULL) { // non-empty subtree ++ copy_root = new trie_node; ++ copy_root->level = level; ++ copy_root->prefixes = node->prefixes; ++ copy_root->prefix_nesting_branches = node->prefix_nesting_branches; ++ copy_root->zero = copy(node->zero, level+1); ++ copy_root->zero_weight = node->zero_weight; ++ copy_root->one = copy(node->one, level+1); ++ copy_root->one_weight = node->one_weight; ++ } else { // empty subtree ++ copy_root = NULL; ++ } ++ // return the pointer to the root node of the copy ++ return copy_root; ++} // end copy() ++ ++ ++void Trie::destruct(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ destruct(node->zero); ++ destruct(node->one); ++ delete node; ++ } ++ return; ++} // end destruct() ++ ++ ++int Trie::compute_weights(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero_weight = compute_weights(node->zero); ++ node->one_weight = compute_weights(node->one); ++ return node->zero_weight + node->one_weight + node->prefixes; ++ } else { // empty subtree ++ return 0; ++ } ++} // end compute_weights() ++ ++ ++float Trie::compute_skew(trie_node* node) { ++ if (node->zero_weight > node->one_weight) { // lighter 1-subtree ++ return 1 - ((float)node->one_weight / (float)node->zero_weight); ++ } else { // lighter 0-subtree ++ return 1 - ((float)node->zero_weight / (float)node->one_weight); ++ } ++} // end compute_skew() ++ ++ ++int Trie::get_prefix_nesting(const trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ // get prefix nesting from successor nodes ++ int zero_nesting = get_prefix_nesting(node->zero); ++ int one_nesting = get_prefix_nesting(node->one); ++ // will this node increase prefix nesting? ++ int is_prefix; ++ if (node->prefixes > 0) { // this is a prefix node ++ is_prefix = 1; ++ } else { ++ is_prefix = 0; ++ } ++ // return maximum of successors' nesting, possibly incremented ++ if (zero_nesting > one_nesting) { ++ return zero_nesting + is_prefix; ++ } else { ++ return one_nesting + is_prefix; ++ } ++ } else { // empty subtree ++ return 0; ++ } ++} // end get_prefix_nesting() ++ ++ ++void Trie::remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches) { ++ trie_node** lightest_subtree_ptr = NULL; ++ int* lightest_weight_ptr = NULL; ++ // find the lightest subtree of nodes stored in the queue ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // auxiliary variables ++ trie_node** subtree_ptr = NULL; ++ int* weight_ptr = NULL; ++ if (one_child) { // consider only nodes with one child ++ // consider only nodes that can become a valid leaf node ++ if (node->prefixes > 0) { ++ // one-subtree only ++ if ((node->zero == NULL) && (node->one != NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ // zero-subtree only ++ } else if ((node->zero != NULL) && (node->one == NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } ++ } ++ } else { // consider only nodes with two children ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // determine lighter subtree ++ if (node->zero_weight <= node->one_weight) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } else { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ } ++ } ++ } ++ // no lightest subtree has been found so far ++ if (lightest_weight_ptr == NULL) { ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } else { // a candidate for the lightest subtree has already been found ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ // new lightest subtree ++ if ((*weight_ptr) < (*lightest_weight_ptr)) { ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } ++ } ++ } // end of while (!q.empty()) ++ // if lightest subtree, which can be removed, has been found ++ if (lightest_subtree_ptr != NULL) { ++ destruct(*lightest_subtree_ptr); ++ *lightest_subtree_ptr = NULL; ++ *lightest_weight_ptr = 0; ++ } ++ return; ++} // end remove_lightest_subtree() ++ ++ ++int Trie::mark_prefix_nesting_branches(trie_node* node, int prefix_nesting, ++ int seen_prefixes) { ++ if (node == NULL) { // empty subtree ++ return 0; ++ } ++ if (node->prefixes > 0) { // the current root node is a prefix node ++ seen_prefixes++; ++ } ++ // when a prefix nesting branch has been found ++ if (seen_prefixes == prefix_nesting) { ++ node->prefix_nesting_branches = 1; ++ } else { // look for maximum prefix nesting branches in subtrees ++ int branches_zero = mark_prefix_nesting_branches(node->zero, ++ prefix_nesting, ++ seen_prefixes); ++ int branches_one = mark_prefix_nesting_branches(node->one, ++ prefix_nesting, ++ seen_prefixes); ++ node->prefix_nesting_branches = branches_zero + branches_one; ++ } ++ return node->prefix_nesting_branches; ++} // end mark_refix_nesting_branches() ++ ++ ++int Trie::get_removable_prefixes(trie_node* node) { ++ if (node == NULL) { ++ return 0; ++ } ++ int removable_prefixes_zero = get_removable_prefixes(node->zero); ++ int removable_prefixes_one = get_removable_prefixes(node->one); ++ int removable_prefixes_this = node->prefixes; ++ // keep at least one prefix in a leaf node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_this--; ++ } ++ // different handling for 2-children node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // allow removing prefixes from subtrees only if both subtrees contain ++ // removable prefixes ++ if ((removable_prefixes_zero > 0) && (removable_prefixes_one > 0)) { ++ // initialize auxiliar variables ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ int d = 1; // divisor of zero_weight and one_weight ++ int x = 0; // to be removed prefixes from zero subtree ++ int y = 0; // to be removed prefixes from one subtree ++ // find x and y such that ++ // a) x <= removable_prefixes_zero ++ // b) y <= removable_prefixes_one ++ // where ++ // x = zero_weight - (zero_weight / gcd) ++ // y = one_weight - (one_weight / gcd) ++ // and gcd is the gratest common divisor of zero_weight and one_weight ++ while ((d <= zero_weight) && (d <= one_weight)) { ++ // if d is the gcd ++ if (((zero_weight % d) == 0) && ((one_weight % d) == 0)) { ++ // if to be removed prefixes from both zero and one subtrees is ++ // smaller than removable prefixes from these subtrees ++ if ((zero_weight - zero_weight / d <= removable_prefixes_zero) ++ && ++ (one_weight - one_weight / d <= removable_prefixes_one)) { ++ x = zero_weight - (zero_weight / d); ++ y = one_weight - (one_weight / d); ++ } else { ++ break; ++ } ++ } ++ d++; ++ } ++ // return the total number of prefixes that can be removed without ++ // altering the skew ++ return removable_prefixes_this + ++ x + ++ y; ++ } else { ++ return removable_prefixes_this; ++ } ++ } else { ++ return removable_prefixes_this + ++ removable_prefixes_zero + ++ removable_prefixes_one; ++ } ++} // end get_removable_prefixes ++ ++ ++void Trie::adjust_node_skew(trie_node* node, float target_skew) { ++ // initialize lighter_* and heavier_* variables ++ int lighter_weight; ++ int heavier_weight; ++ trie_node* lighter_subtree; ++ trie_node* heavier_subtree; ++ // initialize auxiliary variables for skew computation ++ float skew; ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ // compute skew of the given node and set lighter_* and heavier_* variables ++ if (zero_weight > one_weight) { // zero subtree is heavier ++ skew = 1 - ((float)one_weight / (float)zero_weight); ++ lighter_weight = one_weight; ++ heavier_weight = zero_weight; ++ lighter_subtree = node->one; ++ heavier_subtree = node->zero; ++ } else { // one subtree is heavier ++ skew = 1 - ((float)zero_weight / (float)one_weight); ++ lighter_weight = zero_weight; ++ heavier_weight = one_weight; ++ lighter_subtree = node->zero; ++ heavier_subtree = node->one; ++ } ++ // initialize auxiliary variables ++ double new_weight_real; ++ int weight; ++ trie_node* subtree; ++ // decrease working skew - remove prefixes from heavier subtree ++ if ((skew - target_skew) > 0) { ++ new_weight_real = lighter_weight / (1 - target_skew); ++ weight = heavier_weight; ++ subtree = heavier_subtree; ++ // increase working skew - remove prefixes from lighter subtree ++ } else { ++ new_weight_real = heavier_weight * (1 - target_skew); ++ weight = lighter_weight; ++ subtree = lighter_subtree; ++ } ++ // determine new integer weight of a selected subtree ++ int new_weight = round(new_weight_real); ++ // determine number of prefixes that will be removed ++ int remove_prefixes = weight - new_weight; ++ int removable_prefixes = get_removable_prefixes(subtree); ++ if (remove_prefixes > removable_prefixes) { ++ // decrease the number of removed prefixes to the maximum number of ++ // prefixes that can be removed ++ remove_prefixes = removable_prefixes; ++ } ++ // make the selected subtree lighter by removing the given number of ++ //prefixes ++ make_subtree_lighter(subtree, remove_prefixes); ++ compute_weights(node); ++ return; ++} // end adjust_node_skew() ++ ++ ++void Trie::make_subtree_lighter(trie_node* root, int remove_prefixes) { ++ // nothing to do when the subtree is empty or 0 prefixes are to be removed ++ if ((root == NULL) || (remove_prefixes == 0)) { ++ return; ++ } ++ // auxiliary variables for counting statistics ++ trie_node* node = root; ++ int removable_prefixes_node = 0; ++ int removable_prefixes_branch = 0; ++ // in priority queue, nodes with less prefixes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_prefixes> pq; ++ // initialize auxiliary variables (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch = removable_prefixes_node; ++ pq.push(node); ++ } ++ // traverse a non-branching part of the subtree (i.e. up to the closest ++ // 2-children node or a leaf node) and compute basic statistics about it ++ while (((node->zero == NULL) && (node->one != NULL)) || ++ ((node->zero != NULL) && (node->one == NULL))) { ++ // determine the next step ++ if (node->zero == NULL) { ++ node = node->one; ++ } else { ++ node = node->zero; ++ } ++ // compute statistics (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch += removable_prefixes_node; ++ pq.push(node); ++ } ++ } ++ // get the number of removable prefixes in the remaining subtree ++ int removable_prefixes_subtree = get_removable_prefixes(node); ++ int removable_prefixes_zero = 0; ++ // adjust it to not contain removable prefixes of the subtree's root node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_subtree = 0; ++ } else { ++ removable_prefixes_subtree -= node->prefixes; ++ } ++ // get the number of removable prefixes in branches of the remaining subtree ++ if (removable_prefixes_subtree > 0) { ++ int subtree_weight = node->zero_weight + node->one_weight; ++ removable_prefixes_zero = ++ round(((float)node->zero_weight / (float)subtree_weight) * ++ removable_prefixes_subtree); ++ } ++ // do not continue when no removable prefixes in the branch nor the subtree ++ if ((removable_prefixes_branch + removable_prefixes_subtree) == 0) { ++ return; ++ } ++ // distribute prefixes that are to be removed between the branch and the ++ // subtree ++ int remove_prefixes_branch = round(((float)removable_prefixes_branch / ++ (float)(removable_prefixes_subtree + ++ removable_prefixes_branch)) * ++ remove_prefixes); ++ int remove_prefixes_subtree = remove_prefixes - remove_prefixes_branch; ++ // initialize auxiliary variable for test purposes ++ int removed_prefixes_branch = 0; ++ // while there are some prefix nodes in the branch, remove prefixes ++ // proportionally from all these nodes ++ while (!pq.empty()) { ++ // deque the front element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // determine the number of prefixes that are to be removed from this node ++ int remove_prefixes_node; ++ if (!pq.empty()) { // not the last node of the branch ++ // keep at least one prefix in a leaf node ++ removable_prefixes_node = working_node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ // the nuber of prefixes to be removed is computed proportionally ++ remove_prefixes_node = round(((float)removable_prefixes_node / ++ (float)removable_prefixes_branch) * ++ remove_prefixes_branch); ++ } else { // the last node of the branch ++ // the number of prefixes to be removed ensures removing all the remaining prefixes ++ remove_prefixes_node = remove_prefixes_branch - removed_prefixes_branch; ++ } ++ // remove the given number of prefixes ++ working_node->prefixes -= remove_prefixes_node; ++ // adjust the test variable ++ removed_prefixes_branch += remove_prefixes_node; ++ } ++ // the last node in the non-branching part of the subtree is a 2-children ++ // node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // there are some prefixes to be removed from the subtree rooted at node ++ if (remove_prefixes_subtree > 0) { ++ // distribute prefixes that are to be removed from from the subtree ++ // between its zero and one subtrees ++ int remove_prefixes_zero = round(((float)removable_prefixes_zero / ++ (float)removable_prefixes_subtree) * ++ remove_prefixes_subtree); ++ int remove_prefixes_one = remove_prefixes_subtree - ++ remove_prefixes_zero; ++ // remove prefixes from subtrees of the 2-children node ++ compute_weights(node); ++ make_subtree_lighter(node->zero, remove_prefixes_zero); ++ make_subtree_lighter(node->one, remove_prefixes_one); ++ compute_weights(node); ++ } ++ } ++ return; ++} // end make_subtree_lighter() ++ ++ ++trie_node* Trie::remove_nonprefix_branches(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero = remove_nonprefix_branches(node->zero); ++ node->one = remove_nonprefix_branches(node->one); ++ if ((node->zero == NULL) && (node->one == NULL) && ++ (node->prefixes == 0)) { ++ delete node; ++ return NULL; ++ } ++ } ++ return node; ++} //end remove_nonprefix_branches() ++ ++ ++void Trie::adjust_branching(vector branching_one_child, ++ vector branching_two_children) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // recursively compute weight of all subtrees ++ compute_weights(root); ++ // recursively compute maximum prefix nesting ++ int prefix_nesting = get_prefix_nesting(root); ++ // mark branches with maximum prefix nesting ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = -1; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // get pointer to the front element ++ trie_node* node = q.front(); ++ // first node at this level - perform branching adjustment ++ // (all nodes from the current level are enqueued) ++ if (node->level != level) { ++ level = node->level; ++ // compute branching statistics for this level ++ queue q_copy (q); ++ int one_child = 0; ++ int two_children = 0; ++ int sum = 0; ++ while (!q_copy.empty()) { ++ // dequeue front element from the auxiliary queue ++ trie_node* node_copy = q_copy.front(); ++ q_copy.pop(); ++ // increment correct counter ++ if ((node_copy->zero != NULL) && (node_copy->one != NULL)) { ++ two_children++; ++ } else if ((node_copy->zero != NULL) || (node_copy->one != NULL)) { ++ one_child++; ++ } ++ } ++ sum = one_child + two_children; ++ // branching probabilities are defined at this level ++ if (sum != 0) { // there is some branching at this level ++ float current_branching_two = (float) two_children / (float) (sum); ++ // adjust branching by reducing the number of two-children nodes ++ if (current_branching_two > branching_two_children[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = two_children - ++ (branching_two_children[level] * sum); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((two_children - floor(remove_subtrees)) / sum) ++ - branching_two_children[level]; ++ float diff_max = branching_two_children[level] - ++ ((two_children - ceil(remove_subtrees)) / sum); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, false, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ // adjust branching nodes count variables ++ one_child += remove_steps; ++ two_children -= remove_steps; ++ } ++ // removing subtree of one-child nodes can change branching ++ // probabilities ++ if (two_children != 0) { ++ float current_branching_one = (float) one_child / (float) (sum); ++ // adjust branching by reducing the number of one-child nodes ++ if (current_branching_one > branching_one_child[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = ++ ((branching_one_child[level] * sum) - one_child) / ++ (branching_one_child[level] - 1); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((one_child - floor(remove_subtrees)) / ++ (sum - floor(remove_subtrees))) - ++ branching_one_child[level]; ++ float diff_max = branching_one_child[level] - ++ ((one_child - ceil(remove_subtrees)) / ++ (sum - ceil(remove_subtrees))); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, true, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ one_child -= remove_steps; ++ sum -= remove_steps; ++ } ++ } ++ } // end of if (sum != 0) ++ } // end of if (node->level != level) ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // remove the front element from the queue ++ q.pop(); ++ } // end of while (!q.empty()) ++ return; ++} // end adjust_branching() ++ ++ ++void Trie::adjust_skew(vector skew, float skew_epsilon) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ q.push(root); ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element from the queue ++ trie_node* node = q.front(); ++ q.pop(); ++ // store nodes with 2 children into a stack ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ s.push(node); ++ } ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ } ++ // initialize auxiliary variables ++ // in priority queue, lighter nodes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_weight> pq; ++ float total_skew = 0.0; ++ int level; ++ if (!s.empty()) { ++ level = s.top()->level; ++ } ++ // do inverse breadth-first search on two-children nodes ++ while (!s.empty()) { ++ // pop top element from the stack ++ trie_node* node = s.top(); ++ s.pop(); ++ // next level - adjust total skew of the current level ++ if (level != node->level) { ++ // store the number of 2-children nodes at current level ++ int two_children_nodes = pq.size(); ++ // compute target total skew ("sum of all skew values at this level") ++ float target_total_skew = skew[level] * two_children_nodes; ++ // compute skew that is going to be added/removed ++ float skew_change = target_total_skew - total_skew; ++ // compute average skew that is going to be added/removed ++ float average_skew_change; ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ // iteratively adjust total skew at this level ++ while (!pq.empty()) { ++ // skip further skew adjustment when average_skew_change is less ++ // than the given skew_epsilon ++ if (abs(average_skew_change) < skew_epsilon) { ++ // remove remaining nodes from the priority queue ++ while (!pq.empty()) { ++ pq.pop(); ++ } ++ // end the outer "while (!pq.empty())" loop ++ break; ++ } ++ // pop the top element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // compute original skew of the working node ++ float original_skew = compute_skew(working_node); ++ float target_skew = original_skew + skew_change; ++ // adjust skew of the working node ++ if (target_skew < 0.0) { ++ target_skew = 0.0; ++ } else if (target_skew > 1.0) { ++ target_skew = 1.0; ++ } ++ adjust_node_skew(working_node, target_skew); ++ // recursively compute weight of node's subtrees ++ compute_weights(working_node); ++ // compute adjusted skew of the working node ++ float adjusted_skew = compute_skew(working_node); ++ // update total skew, skew that is going to be added/removed, and ++ // its average value ++ total_skew = total_skew - original_skew + adjusted_skew; ++ skew_change = target_total_skew - total_skew; ++ two_children_nodes = pq.size(); ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ } ++ level = node->level; ++ total_skew = 0.0; ++ } ++ // recursively compute weight of node's subtrees ++ compute_weights(node); ++ // insert the node into the priority queue ++ pq.push(node); ++ // actualize total skew value ++ total_skew += compute_skew(node); ++ } ++ return; ++} // end adjust_skew() ++ ++ ++void Trie::adjust_prefixes(vector prefixes_proportion, ++ const int target_size) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute the total number of prefixes at each level ++ vector all_prefixes(129,0); ++ queue q; ++ q.push(root); ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // update the total number of prefixes at current level ++ all_prefixes[node->level] += node->prefixes; ++ } ++ // compute the number of target and to be removed prefixes at each level ++ vector target_prefixes(129,0); ++ vector remove_prefixes(129,0); ++ int target_prefixes_total = 0; ++ int leaf_level = 0; ++ for (int i = 0; i < (int) prefixes_proportion.size(); i++) { ++ target_prefixes[i] = round(prefixes_proportion[i]*target_size); ++ target_prefixes_total += target_prefixes[i]; ++ remove_prefixes[i] = all_prefixes[i] - target_prefixes[i]; ++ if (target_prefixes[i] != 0) { ++ leaf_level = i; ++ } ++ } ++ // final correction to given target_size ++ if (target_prefixes_total != target_size) { ++ int diff = target_size - target_prefixes_total; ++ target_prefixes[leaf_level] += diff; ++ target_prefixes_total += diff; ++ remove_prefixes[leaf_level] -= diff; ++ } ++ // compute the number of prefixes to be removed at remaining levels ++ vector remove_prefixes_remaining(129,0); ++ for (int i = 127; i >= 0; i--) { ++ remove_prefixes_remaining[i] = remove_prefixes_remaining[i+1] + ++ remove_prefixes[i+1]; ++ } ++ // starting from the root, adjust prefixes distribution ++ queue nodes; ++ nodes.push(root); ++ queue remove_prefixes_subtrees; ++ remove_prefixes_subtrees.push(remove_prefixes[0] + remove_prefixes_remaining[0]); ++ int level = -1; ++ while (!nodes.empty()) { ++ // get the front element ++ // (from both nodes and remove_prefixes_subtrees queues) ++ trie_node* node = nodes.front(); ++ // next level - adjust prefixes at this level ++ // (all nodes of this level are stored in nodes queue) ++ if (node->level != level) { ++ level = node->level; ++ // actualize subtrees' weight information in nodes ++ compute_weights(root); ++ // initialize vectors to contain all current elements of queues ++ queue nodes_copy (nodes); ++ vector nodes_vect; ++ queue remove_prefixes_subtrees_copy (remove_prefixes_subtrees); ++ vector remove_prefixes_subtrees_vect; ++ while (!nodes_copy.empty()) { ++ nodes_vect.push_back(nodes_copy.front()); ++ nodes_copy.pop(); ++ remove_prefixes_subtrees_vect.push_back(remove_prefixes_subtrees_copy.front()); ++ remove_prefixes_subtrees_copy.pop(); ++ } ++ // from all leaf nodes at this level ++ // remove prefixes that have to be removed ++ int i = 0; ++ while (i < (int) nodes_vect.size()) { ++ if ((nodes_vect[i]->zero == NULL) && ++ (nodes_vect[i]->one == NULL)) { ++ // determine the real number of prefixes to be removed ++ // (do not remove the last prefix from a leaf node) ++ int remove_prefixes_node; ++ if (nodes_vect[i]->prefixes > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } else { ++ remove_prefixes_node = nodes_vect[i]->prefixes - 1; ++ } ++ // consider all prefixes of this node and this subtree to be ++ // removed, regardless they are really removed or not ++ // (in any case, there are no other prefixes that could be ++ // removed) ++ all_prefixes[level] -= nodes_vect[i]->prefixes; ++ remove_prefixes_subtrees_vect[i] = 0; ++ // remove the prefixes ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ // remove this node from both vectors ++ nodes_vect.erase(nodes_vect.begin()+i); ++ remove_prefixes_subtrees_vect.erase(remove_prefixes_subtrees_vect.begin()+i); ++ } else { ++ // the node has not been removed, thus increase the index ++ i++; ++ } ++ } ++ // if there are some nodes with prefixes that could be removed AND ++ // the number of prefixes to be removed is not negative ++ if ((all_prefixes[level] > 0) && (remove_prefixes[level] >= 0)) { ++ // initialize auxiliary constant (for this level) ++ float remove_all_ratio = (float)(remove_prefixes[level]) / ++ (float)(all_prefixes[level]); ++ // from all non-leaf nodes at this level ++ // remove prefixes that are to be removed at this level ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ int remove_prefixes_node = round((float)(nodes_vect[i]->prefixes) * ++ remove_all_ratio); ++ // do not remove more than all prefixes to be removed from this subtree ++ if (remove_prefixes_node > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } ++ // do not remove more than all prefixes of this node ++ if (remove_prefixes_node > nodes_vect[i]->prefixes) { ++ remove_prefixes_node = nodes_vect[i]->prefixes; ++ } ++ // remove the prefixes and adjust other variables ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ all_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes_subtrees_vect[i] -= remove_prefixes_node; ++ } ++ } ++ // for all nodes at this level ++ // distribute prefixes to be removed in a subtree rooted at this node ++ // into node's subtrees ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ // distribution for 2-children nodes ++ if ((nodes_vect[i]->zero != NULL) && (nodes_vect[i]->one != NULL)) { ++ // determine the distribution ++ int total_weight = nodes_vect[i]->zero_weight + ++ nodes_vect[i]->one_weight; ++ int remove_prefixes_zero = round(((float)(nodes_vect[i]->zero_weight) / ++ (float)total_weight) * ++ (float)(remove_prefixes_subtrees_vect[i])); ++ int remove_prefixes_one = remove_prefixes_subtrees_vect[i] - ++ remove_prefixes_zero; ++ // do not remove more than all prefixes from zero subtree ++ if (remove_prefixes_zero > nodes_vect[i]->zero_weight) { ++ remove_prefixes_zero = nodes_vect[i]->zero_weight; ++ } ++ // do not remove more than all prefixes from one subtree ++ if (remove_prefixes_one > nodes_vect[i]->one_weight) { ++ remove_prefixes_one = nodes_vect[i]->one_weight; ++ } ++ // store the distribution into main queues ++ nodes.push(nodes_vect[i]->zero); ++ remove_prefixes_subtrees.push(remove_prefixes_zero); ++ nodes.push(nodes_vect[i]->one); ++ remove_prefixes_subtrees.push(remove_prefixes_one); ++ } else { ++ // distribution for 1-child nodes ++ if (nodes_vect[i]->zero != NULL) { ++ nodes.push(nodes_vect[i]->zero); ++ } else if (nodes_vect[i]->one != NULL) { ++ nodes.push(nodes_vect[i]->one); ++ } ++ remove_prefixes_subtrees.push(remove_prefixes_subtrees_vect[i]); ++ } ++ } ++ } ++ // remove the front elements from the main queues ++ nodes.pop(); ++ remove_prefixes_subtrees.pop(); ++ } ++ return; ++} // end adjust_prefixes() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++// Default constructor ++Trie::Trie() { ++ root = NULL; ++} // end Trie() ++ ++ ++// Copy constructor ++Trie::Trie(const Trie& orig) { ++ root = copy(orig.get_root(), 0); ++} // end Trie() ++ ++ ++// Destructor ++Trie::~Trie() { ++ destruct(root); ++} // end ~Trie() ++ ++ ++// Copy assignment ++Trie& Trie::operator= (const Trie& orig) { ++ // replace the original trie by a copy of the assigned trie ++ destruct(root); ++ root = copy(orig.get_root(), 0); ++ // return created object ++ return *this; ++} // end operator= () ++ ++ ++void Trie::insert(const IP_prefix& pref) { ++ // insert at least a root node when the trie is empty ++ if (root == NULL) { ++ root = new trie_node; ++ root->level = 0; ++ root->prefixes = 0; ++ root->prefix_nesting_branches = 0; ++ root->zero = NULL; ++ root->zero_weight = 0; ++ root->one = NULL; ++ root->one_weight = 0; ++ } ++ // insert the given prefix into the trie ++ if (pref.get_length() == 0) { // prefix of length 0 ++ (root->prefixes)++; ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** next_node_ptr; ++ string prefix = pref.get_prefix(); ++ // trie traversal ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node and store the pointer to it ++ if (prefix[i] == '0') { ++ next_node_ptr = &(node->zero); ++ } else { // (prefix[i] == '1') ++ next_node_ptr = &(node->one); ++ } ++ // insert the next node if it does not exist ++ if ((*next_node_ptr) == NULL) { ++ (*next_node_ptr) = new trie_node; ++ (*next_node_ptr)->level = i+1; ++ (*next_node_ptr)->prefixes = 0; ++ (*next_node_ptr)->prefix_nesting_branches = 0; ++ (*next_node_ptr)->zero = NULL; ++ (*next_node_ptr)->zero_weight = 0; ++ (*next_node_ptr)->one = NULL; ++ (*next_node_ptr)->one_weight = 0; ++ } ++ // move to the next node; ++ node = (*next_node_ptr); ++ } ++ // prefix insertion ++ (node->prefixes)++; ++ } ++ return; ++} // end insert() ++ ++ ++bool Trie::erase(const IP_prefix& pref) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return root; ++ } ++ // search for the given prefix ++ if (pref.get_length() == 0) { // prefix of length 0 ++ if (root->prefixes > 0) { // we have found the prefix node ++ (root->prefixes)--; ++ if ((root->prefixes == 0) && ++ (root->zero == NULL) && ++ (root->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(root); ++ root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** destruct_root = &(root); ++ string prefix = pref.get_prefix(); ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node ++ if (prefix[i] == '0') { ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->one != NULL)) { // this node cannot be removed ++ destruct_root = &(node->zero); ++ } ++ // move to the next node ++ node = node->zero; ++ } else { // (prefix[i] == '1') ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->zero != NULL)) { // this node cannot be removed ++ destruct_root = &(node->one); ++ } ++ // move to the next node ++ node = node->one; ++ } ++ // chceck whether the next node exists (terminate search if not) ++ if (node == NULL) { ++ return false; ++ } ++ } ++ if (node->prefixes > 0) { // we have found the prefix node ++ (node->prefixes)--; ++ if ((node->prefixes == 0) && ++ (node->zero == NULL) && ++ (node->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(*destruct_root); ++ *destruct_root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } ++} // end erase() ++ ++ ++void Trie::prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations) { ++ // get original prefix set size ++ trie_stats s; ++ this->get_stats(s); ++ int orig_size = s.classbench.prefixes; ++ ++ // adjust branching (1st step of trie pruning) ++ this->adjust_branching(one_child, two_children); ++ ++ // iteratively adjust skew and prefixes proportion ++ // (multiple iterations help to reduce the negative effect of ++ // adjust_prefixes function on skew) ++ for (int i = 1; i <= iterations; i++) { ++ // adjust skew (2nd step of trie pruning) ++ this->adjust_skew(skew); ++ // adjust prefixes proportion (3rd step of trie pruning) ++ if (i == iterations) { ++ this->adjust_prefixes(prefixes, target_size); ++ } else { ++ this->adjust_prefixes(prefixes, round((1-(float)i/4)*orig_size)); ++ } ++ } ++} // end prune() ++ ++ ++void Trie::get_stats(trie_stats& stats) { ++ // initialize classbench statistics ++ stats.classbench.prefixes = 0; ++ stats.classbench.prefix_lengths = vector(129,0); ++ stats.classbench.branching_one_child = vector(129,0.0); ++ stats.classbench.branching_two_children = vector(129,0.0); ++ stats.classbench.skew = vector(129,0.0); ++ stats.classbench.prefix_nesting = 0; ++ // initialize nodes statistics ++ stats.nodes.leaf = vector(129,0); ++ stats.nodes.one_child = vector(129,0); ++ stats.nodes.two_children = vector(129,0); ++ stats.nodes.prefix = vector(129,0); ++ stats.nodes.non_prefix = vector(129,0); ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute zero_weight and one_weight in each node of the trie ++ compute_weights(root); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = root->level; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // level change - finish statistics computation for the previous level ++ if (node->level != level) { ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // increment the level counter ++ level++; ++ } ++ // trie node visit - classbench statistics ++ stats.classbench.prefixes += node->prefixes; ++ stats.classbench.prefix_lengths[level] += node->prefixes; ++ if ((node->zero != NULL) && (node->one != NULL)) { // skew is defined ++ stats.classbench.skew[level] += compute_skew(node); ++ } ++ // trie node visit - nodes statistics ++ if (node->zero == NULL) { ++ if (node->one == NULL) { // leaf node ++ (stats.nodes.leaf[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } else { // node->zero != NULL ++ if (node->one != NULL) { // two child node ++ (stats.nodes.two_children[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } ++ if (node->prefixes > 0) { // prefix node ++ (stats.nodes.prefix[level])++; ++ } else { // non-prefix node ++ (stats.nodes.non_prefix[level])++; ++ } ++ } // end of while (!q.empty()) ++ // finish statistics computation for the last level ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // compute prefix nesting ++ stats.classbench.prefix_nesting = get_prefix_nesting(root); ++ return; ++} // end get_stats() +diff --git a/trie.h b/trie.h +new file mode 100644 +index 0000000..4cbe414 +--- /dev/null ++++ b/trie.h +@@ -0,0 +1,477 @@ ++// trie.h: header file for trie class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef TRIE_H ++#define TRIE_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++/* ++ * Structure representing a node of a trie. ++ * ++ * Each node can be a prefix node (prefixes > 0) or a non-prefix node ++ * (prefixes = 0) and it can have at most two successors accessible using ++ * pointers zero (when the next bit of the prefix is 0) or one (when the next ++ * bit of the prefix is 1). ++ * Except these basic members, each trie node stores some other values that ++ * make the computation of trie characteristics easier. These values are ++ * further described directly in the trie node structure declaration. ++ */ ++ ++struct trie_node { ++ // trie level (i.e. distance from the root) at which the node resides ++ int level; ++ ++ // number of occurences of the prefix ++ int prefixes; ++ ++ // counter of branches with maximum prefix nesting that this node is part of ++ int prefix_nesting_branches; ++ ++ // 0-subtree-related members ++ trie_node* zero; // pointer to the subtree root ++ int zero_weight; // number of prefixes in the subtree ++ ++ // 1-subtree-related members ++ trie_node* one; // pointer to the subtree root ++ int one_weight; // number of prefixes in the subtree ++}; ++ ++/* ++ * Structure representing trie statistics proposed in the ClassBench tool. ++ * ++ * Vector members store statistics defined separately for each level of the ++ * trie. Prefix nesting is defined for the whole trie. ++ */ ++struct classbench_stats { ++ // total number of prefixes ++ int prefixes; ++ ++ // number of prefixes (not prefix nodes) with given length ++ vector prefix_lengths; ++ ++ // probability of node with only one child (from all non-leaf nodes) ++ vector branching_one_child; ++ // probability of node with two children (from all non-leaf nodes) ++ vector branching_two_children; ++ ++ // average relative weight ratio of lighter vs heavier subtree ++ // (nodes with two children only) ++ vector skew; ++ ++ // maximum number of prefix nodes on an arbitrary path in the trie ++ int prefix_nesting; ++}; ++ ++/* ++ * Structure representing statistics related to trie nodes. ++ * ++ * All the statistics are stored separately for each level of the trie. ++ */ ++struct node_stats { ++ vector leaf; // number of leaf nodes ++ vector one_child; // number of nodes with one child only ++ vector two_children; // number of nodes with both children ++ vector prefix; // number of prefix nodes (not prefixes) ++ vector non_prefix; // number of non-prefix nodes ++}; ++ ++/* ++ * Structure representing statistics related to the trie. ++ * ++ * Statistics are divided into two groups: ++ * 1) statistics proposed in ClassBench tool and ++ * 2) statistics related to trie nodes. ++ */ ++struct trie_stats { ++ classbench_stats classbench; // ClassBench statistics ++ node_stats nodes; // nodes statistics ++}; ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a binary prefix tree - trie. ++ * ++ * Class functions do not adjust zero_weight and one_weight counters in a trie ++ * node by default. These feilds are viewed as place holders and they can be ++ * set to the correct value by calling the compute_weights(). ++ */ ++class Trie { ++ private: ++ /* ++ * Pointer to the root node of the trie. ++ */ ++ trie_node* root; ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++// (MAYBE JUST ONE REASON -- BY COPYING ONLY A SUBTREE YOU LOOSE THE ++// INFORMATION ABOUT THE COMMON PREFIX, I.E. PATH IN TRIE PRECEDING THIS ++// SUBTREE) ++ /* ++ * Private static function for copying a subtree of the trie, where the ++ * subtree is specified by a pointer to its root node. ++ * Trie node members prefixes, zero_weight, and one_weight are copied ++ * without any change, while the level member is set to the given value. ++ * This approach allows e.g. to create a new valid trie by copying the ++ * given subtree. (In such a case the level parameter have to be set to ++ * 0 during the initial function call.) ++ * Trie node members zero and one are set to the values returned by the ++ * recursive call of the copy() onto the 0-subtree and 1-subtree, ++ * respectively. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * copied. ++ * @param level Value for the level member of the copied trie node. ++ * @return Pointer to the root node of the copy. ++ */ ++ static trie_node* copy(const trie_node* node, int level); ++ ++ /* ++ * Private static function for destruction of a trie's subtree. The ++ * subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * destructed. ++ */ ++ static void destruct(trie_node* node); ++ ++ /* ++ * Private static function for computation of zero_weight and one_weight ++ * values of all the trie nodes in a given subtree. The subtree is given ++ * by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * weights are to be computed. ++ * @return Weights of the given subtree. ++ */ ++ static int compute_weights(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of node's skew as defined in ++ * the ClassBench paper. This function expects that the pointed node is ++ * a 2-children node and that its fields zero_weight and one_weight ++ * contain valid values. ++ * @param node Pointer to the node of which the skew is going to be ++ * computed. ++ * @return Skew of the given node. ++ */ ++ static float compute_skew(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that determines the maximum prefix nesting in ++ * a given subtree, i.e. the maximum number of prefixes on any path from ++ * the root to the leaves in the subtree. The subtree is given by a ++ * pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * prefix nesting is to be computed. ++ * @return Maximum prefix nesting in the given subtree. ++ */ ++ static int get_prefix_nesting(const trie_node* node); ++ ++ /* ++ * Private static function that removes the lightest subtree among trie ++ * nodes passed in a queue. The lightest subtree can be selected ++ * either among one-child nodes or two-children nodes. The selection is ++ * done in such a way that when the lightest subtree is removed, there ++ * is still at least one branch with maximum prefix nesting in the trie. ++ * After removing the lightest subtree, corresponding subtree weight is ++ * set to 0. ++ * @param q Queue with trie nodes that are to be ++ * inspected. ++ * @param one_child Select lightest subtree either among ++ * one-child nodes (TRUE) or ++ * two-children nodes (FALSE). ++ * @param prefix_nesting_branches The number of branches in the trie ++ * with maximum prefix nesting. ++ */ ++ static void remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches); ++ ++ /* ++ * Private static function for marking branches with maximum prefix ++ * nesting in a given subtree. The subtree is given by a pointer to its ++ * root node. Maximum prefix nesting is specified as a parameter of the ++ * function (therefore, it has to be computed outside the function). ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in ++ * which prefix nesting branches are to be ++ marked. ++ * @param prefix_nesting Maximum prefix nesting in the given subtree. ++ * @param seen_prefixes Number of prefixes that has been seen so far. ++ * @return Weights of the given subtree. ++ */ ++ static int mark_prefix_nesting_branches(trie_node* node, ++ int prefix_nesting, ++ int seen_prefixes); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of the maximum number of ++ * prefixes that can be removed from a given subtree. When computing the ++ * result of this function, the following contraints are taken into ++ * account: ++ * * no prefix node within the subtree must not become a non-prefix ++ * node after removing the prefixes; ++ * * removing the prefixes from subtrees of 2-children node should not ++ * alter the skew of this node. ++ * The subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A Pointer to the root node of the subtree in which the ++ number of removable prefixes is going to be computed. ++ * @return The number of removable prefixes in the given subtree. ++ */ ++ static int get_removable_prefixes(trie_node* node); ++ ++ /* ++ * Private static function for adjusting skew of a specified node to the ++ * given value. The node is specified by it's pointer and the target ++ * skew is given as a float number. ++ * @param node Pointer to the node whose skew is going to be ++ * adjusted. ++ * @param target_skew The value to which the node's skew should be ++ * adjusted. ++ */ ++ static void adjust_node_skew(trie_node* node, float target_skew); ++ ++ /* ++ * Private static function that removes the given number of prefixes from ++ * a subtree specified by the pointer to its root node. Prefixes are ++ * removed as equally as possible while following a rule that no prefix ++ * node can be turned to a non-prefix node. Removing of prefixes is ++ * performed over all prefix nodes from the root node up to the closest ++ * 2-children node or a leaf node... ++ * @param root Pointer to the root node of the subtree in which ++ * prefixes are going to be removed. ++ * @remove_prefixes The number of prefixes that should be removed from ++ * the specified subtree. ++ */ ++ static void make_subtree_lighter(trie_node* root, int remove_prefixes); ++ ++ /* ++ * Private static function for removing branches without a prefix node ++ * from a given subtree. The subtree is given by a pointer to its root ++ * node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which ++ * nonprefix are to be removed. ++ * @return actualized pointer to the subtree's root node ++ * (NULL when the whole subtree was removed) ++ */ ++ static trie_node* remove_nonprefix_branches(trie_node* node); ++ ++ /* ++ * Private function that removes some subtrees in order to achieve ++ * branching probabilities that are as close as possible to the given ++ * values. ++ * Modifications are done on a per level basis, starting from the root ++ * node. Changes at each level are done in two steps: ++ * 1) lightest subtrees of two-children nodes are removed to achieve ++ * given branching_two_children probability ++ * 2) lightest subtrees of one-child nodes are removed to achieve ++ * given branching_one_child probability ++ * @param branching_one_child Vector specifying probability of ++ * occurence of a trie node with one ++ * child at the given level of the trie. ++ * @param branching_two_children Vector specifying probability of ++ * occurence of a trie node with two ++ * children at the given level of the ++ * trie. ++ */ ++ void adjust_branching(vector branching_one_child, ++ vector branching_two_children); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve an ++ * average skew that is as close as possible to the given values for ++ * particular levels. ++ * Prefixes are removed on a per level basis, starting from the lowest ++ * level. At each level, an average skew is increased/decreased by ++ * removing prefixes from lighter/heavier subtree of the level's nodes. ++ * This adjustment starts from nodes with the lightest subtrees ++ * (adjusting their skew requires removing of the lowest number of ++ * prefixes) and it is implemented such that it (almost) does not change ++ * a skew of nodes at lower levels. ++ * @param skew Vector specifying an average skew at all levels of ++ * the trie. ++ * @ skew_epsilon Threshold value for average skew change at not yet ++ * adjusted nodes (skew adjustment stops when average ++ * skew change is less than the given skew_epsilon). ++ */ ++ void adjust_skew(vector skew, float skew_epsilon = 0.01); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve ++ * prefixes distribution that is as close as possible to the given values ++ * for particular levels. ++ * Prefixes are removed on a per level basis, starting from the root ++ * node. Removing the prefixes consists of three steps: ++ * 1) removing the prefixes from leaf nodes (the last prefix ++ * represented by a leaf node is never removed) ++ * 2) removing the prefixes from non-leaf nodes, proportionally to ++ * their weight ++ * 3) distributing prefixes that are to be removed at lower levels to ++ * subtrees of non-leaf nodes (this distribution is driven by skew) ++ * @param prefixes_proportion Vector that for all trie levels specifies ++ * proportion of prefixes at the given level ++ * to all prefixes in the trie. ++ * @param target_size Target total number of prefixes in the ++ * trie. ++ */ ++ void adjust_prefixes(vector prefixes_proportion, ++ const int target_size); ++ ++ public: ++ /* ++ * Default constructor. ++ * Pointer to the root node is initialized to NULL. ++ */ ++ Trie(); ++ ++ /* ++ * Copy constructor. ++ * Pointer to the root node is initialized by the result of the private ++ * copy(). ++ * @param orig Reference to the original trie object. ++ */ ++ Trie(const Trie& orig); ++ ++ /* ++ * Destructor. ++ * Trie specified by the root pointer is destructed by the private ++ * destruct(). ++ */ ++ ~Trie(); ++ ++ /* ++ * Copy assignment. ++ * Original trie is destructed by the private destruct() and the new trie ++ * is created by the private copy(). ++ * @param orig Reference to the original trie object. ++ * @return Reference to the new trie object. ++ */ ++ Trie& operator= (const Trie& orig); ++ ++ /* ++ * Get function for the root pointer. ++ * @return Pointer to the root node of the trie. ++ */ ++ inline const trie_node* get_root() const { ++ return root; ++ } // end get_root() ++ ++ /* ++ * Inserts the specified prefix into the trie. ++ * The trie is non-recursively traversed to the corresponding trie node, ++ * where the prefix is newly inserted or at least the counter of its ++ * occurences is incremented. ++ * All the missing nodes on a way to the prefix node are newly created ++ * and inserted into the trie as non-prefix nodes. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be inserted. ++ */ ++ void insert(const IP_prefix& pref); ++ ++ /* ++ * Erases the specified prefix from the trie. ++ * The prefix is searched by non-recursively traversing the trie. If the ++ * erase() finds the prefix, the counter of its occurences is decremented ++ * and return value is set to TRUE. ++ * If the erased prefix was the last one (i.e. prefix node has changed to ++ * non-prefix node) and there is not more specific prefix (i.e. prefix ++ * node is a leaf node of the trie), its corresponding node and all its ++ * non-prefix predecessors (up to the closest node with two children) are ++ * removed from the trie using private destruct(). ++ * If the erase() does not find the prefix, it silently ends without any ++ * further action and with return value set to FALSE. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be removed. ++ * @return TRUE if the prefix was removed, ++ * FALSE otherwise. ++ */ ++ bool erase(const IP_prefix& pref); ++ ++ /* ++ * Prunes the trie in order to achieve the given characteristics. ++ * The function first adjusts branching probability distributions at all ++ * trie levels. Next, average skew and prefix length distributions are ++ * adjusted while the number of prefixes in the trie is iteratively ++ * decreased towards the given target size. ++ * @param target_size Target number of prefixes in the trie. The ++ * final number of prefixes in the pruned trie can ++ * be slightly different. ++ * @param prefixes The vector of target prefix length distribution ++ * over the trie levels. ++ * @param one_child The vector of target one-child branching ++ * probability distribution over the trie levels. ++ * @param two_children The vector of target two-children branching ++ * probability distribution over the trie levels. ++ * @param skew The vector of target average skew distribution ++ * over the trie levels. ++ * @param iterations The number of iterations of average skew and ++ * prefix length distribution adjustment. ++ */ ++ void prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations = 4); ++ ++ /* ++ * Computes all defined trie statistics and stores them into a given ++ * structure. ++ * Except prefix nesting, which is computed during separate recursive ++ * traversal, all the other statistics are computed during single ++ * breadth-first search. Following statistics are actualized when ++ * visiting the nodes: ++ * * classbench.prefix_lengths ++ * * classbench.skew ++ * * nodes.leaf ++ * * nodes.one_child ++ * * nodes.two_children ++ * * nodes.prefix ++ * * nodes.non_prefix ++ * The value classbech.skew is also adjusted (divided by ++ * nodes.two_children) after visiting all the nodes at the current trie ++ * level. ++ * There are also two statistics (classbench.branching_one_child and ++ * classbench.branching_two_children) that are fully computed after ++ * visiting all the nodes at the current trie level. Their computation is ++ * based on values nodes.one_child and nodes.two_children. ++ * @param stats Reference to a data structure for computed trie ++ * statistics. ++ */ ++ void get_stats(trie_stats& stats); ++}; ++ ++#endif diff --git a/patches/improvements_ipv6.patch b/patches/improvements_ipv6.patch new file mode 100644 index 0000000..5a8f61f --- /dev/null +++ b/patches/improvements_ipv6.patch @@ -0,0 +1,11178 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } +diff --git a/FilterList.cc b/FilterList.cc +index c123529..4677276 100644 +--- a/FilterList.cc ++++ b/FilterList.cc +@@ -11,6 +11,9 @@ + + #include "stdinc.h" + #include "FilterList.h" ++#include ++ ++namespace ip = std::experimental::net::ip; + + FilterList::FilterList() { + first = last = NULL; +@@ -20,6 +23,9 @@ FilterList::FilterList() { + FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -57,7 +63,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +78,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +116,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -125,35 +131,66 @@ void FilterList::push(struct filter filt) { + + // Print the contents of the FilterList. + void FilterList::print(FILE* fp) { +- int addr[4]; +- unsigned temp; ++ uint128_t temp; + struct FilterList_item *tempfilt; + + for (tempfilt = first; tempfilt != NULL; tempfilt = tempfilt->next){ + // Print new filter character + fprintf(fp,"@"); +- // Print source address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = tempfilt->filt.sa; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- tempfilt->filt.sa_len); +- // Print destination address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = tempfilt->filt.da; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- tempfilt->filt.da_len); ++ // Print source/destination addresses ++ if (ADDRLEN == 32) { // IPv4 ++ // Source address ++ temp = tempfilt->filt.sa >> 96; ++ ip::address_v4 src_addr(temp); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), (tempfilt->filt.sa_len < 32) ? tempfilt->filt.sa_len : 32); ++ // Destination address ++ temp = tempfilt->filt.da >> 96; ++ ip::address_v4 dst_addr(temp); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), (tempfilt->filt.da_len < 32) ? tempfilt->filt.da_len : 32); ++ } else { // IPv6 ++ // Source address ++ temp = tempfilt->filt.sa; ++ const ip::address_v6::bytes_type src_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 src_addr(src_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), tempfilt->filt.sa_len); ++ // Destination address ++ temp = tempfilt->filt.da; ++ const ip::address_v6::bytes_type dst_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 dst_addr(dst_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), tempfilt->filt.da_len); ++ } + // Print source port + fprintf(fp, "%d : %d\t", + tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; +diff --git a/PrefixList.cc b/PrefixList.cc +index a3df1dc..c3e23e5 100644 +--- a/PrefixList.cc ++++ b/PrefixList.cc +@@ -11,21 +11,21 @@ + #include "PrefixList.h" + + PrefixList::PrefixList() { +- N = 65; ++ N = 257; + cdist = 0; + prefixes = new struct prefix*[25]; + for (int type = 0; type < 25; type++){ + prefixes[type] = new struct prefix[N]; + for (int i = 0; i < N; i++) { + prefixes[type][i].prob = 0; +- for (int j = 0; j < 33; j++) prefixes[type][i].sprob[j] = 0; ++ for (int j = 0; j < 129; j++) prefixes[type][i].sprob[j] = 0; + } + } + } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ +@@ -102,14 +102,14 @@ void PrefixList::read_type(int type, FILE *fp) { + int tlen = 0; + int slen = 0; + float prob = 0; +- int lens[34]; +- float probs[34]; +- char scomm[500]; +- int scomm_len = 500; ++ int lens[130]; ++ float probs[130]; ++ char scomm[2000]; ++ int scomm_len = 2000; + while (done == 0) { + fgets(scomm,scomm_len,fp); + // Read a line of the input +- matches = sscanf(scomm,"%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f",&lens[0],&probs[0],&lens[1],&probs[1],&lens[2],&probs[2],&lens[3],&probs[3],&lens[4],&probs[4],&lens[5],&probs[5],&lens[6],&probs[6],&lens[7],&probs[7],&lens[8],&probs[8],&lens[9],&probs[9],&lens[10],&probs[10],&lens[11],&probs[11],&lens[12],&probs[12],&lens[13],&probs[13],&lens[14],&probs[14],&lens[15],&probs[15],&lens[16],&probs[16],&lens[17],&probs[17],&lens[18],&probs[18],&lens[19],&probs[19],&lens[20],&probs[20],&lens[21],&probs[21],&lens[22],&probs[22],&lens[23],&probs[23],&lens[24],&probs[24],&lens[25],&probs[25],&lens[26],&probs[26],&lens[27],&probs[27],&lens[28],&probs[28],&lens[29],&probs[29],&lens[30],&probs[30],&lens[31],&probs[31],&lens[32],&probs[32],&lens[33],&probs[33]); ++ matches = sscanf(scomm,"%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f\t%d,%f",&lens[0],&probs[0],&lens[1],&probs[1],&lens[2],&probs[2],&lens[3],&probs[3],&lens[4],&probs[4],&lens[5],&probs[5],&lens[6],&probs[6],&lens[7],&probs[7],&lens[8],&probs[8],&lens[9],&probs[9],&lens[10],&probs[10],&lens[11],&probs[11],&lens[12],&probs[12],&lens[13],&probs[13],&lens[14],&probs[14],&lens[15],&probs[15],&lens[16],&probs[16],&lens[17],&probs[17],&lens[18],&probs[18],&lens[19],&probs[19],&lens[20],&probs[20],&lens[21],&probs[21],&lens[22],&probs[22],&lens[23],&probs[23],&lens[24],&probs[24],&lens[25],&probs[25],&lens[26],&probs[26],&lens[27],&probs[27],&lens[28],&probs[28],&lens[29],&probs[29],&lens[30],&probs[30],&lens[31],&probs[31],&lens[32],&probs[32],&lens[33],&probs[33],&lens[34],&probs[34],&lens[35],&probs[35],&lens[36],&probs[36],&lens[37],&probs[37],&lens[38],&probs[38],&lens[39],&probs[39],&lens[40],&probs[40],&lens[41],&probs[41],&lens[42],&probs[42],&lens[43],&probs[43],&lens[44],&probs[44],&lens[45],&probs[45],&lens[46],&probs[46],&lens[47],&probs[47],&lens[48],&probs[48],&lens[49],&probs[49],&lens[50],&probs[50],&lens[51],&probs[51],&lens[52],&probs[52],&lens[53],&probs[53],&lens[54],&probs[54],&lens[55],&probs[55],&lens[56],&probs[56],&lens[57],&probs[57],&lens[58],&probs[58],&lens[59],&probs[59],&lens[60],&probs[60],&lens[61],&probs[61],&lens[62],&probs[62],&lens[63],&probs[63],&lens[64],&probs[64],&lens[65],&probs[65],&lens[66],&probs[66],&lens[67],&probs[67],&lens[68],&probs[68],&lens[69],&probs[69],&lens[70],&probs[70],&lens[71],&probs[71],&lens[72],&probs[72],&lens[73],&probs[73],&lens[74],&probs[74],&lens[75],&probs[75],&lens[76],&probs[76],&lens[77],&probs[77],&lens[78],&probs[78],&lens[79],&probs[79],&lens[80],&probs[80],&lens[81],&probs[81],&lens[82],&probs[82],&lens[83],&probs[83],&lens[84],&probs[84],&lens[85],&probs[85],&lens[86],&probs[86],&lens[87],&probs[87],&lens[88],&probs[88],&lens[89],&probs[89],&lens[90],&probs[90],&lens[91],&probs[91],&lens[92],&probs[92],&lens[93],&probs[93],&lens[94],&probs[94],&lens[95],&probs[95],&lens[96],&probs[96],&lens[97],&probs[97],&lens[98],&probs[98],&lens[99],&probs[99],&lens[100],&probs[100],&lens[101],&probs[101],&lens[102],&probs[102],&lens[103],&probs[103],&lens[104],&probs[104],&lens[105],&probs[105],&lens[106],&probs[106],&lens[107],&probs[107],&lens[108],&probs[108],&lens[109],&probs[109],&lens[110],&probs[110],&lens[111],&probs[111],&lens[112],&probs[112],&lens[113],&probs[113],&lens[114],&probs[114],&lens[115],&probs[115],&lens[116],&probs[116],&lens[117],&probs[117],&lens[118],&probs[118],&lens[119],&probs[119],&lens[120],&probs[120],&lens[121],&probs[121],&lens[122],&probs[122],&lens[123],&probs[123],&lens[124],&probs[124],&lens[125],&probs[125],&lens[126],&probs[126],&lens[127],&probs[127],&lens[128],&probs[128],&lens[129],&probs[129]); + // printf("matches = %d, tlen = %d, prob = %.4f\n",matches,lens[0],probs[0]); + if (matches >= 4) { + // Assign total probability +@@ -155,16 +155,16 @@ void PrefixList::smooth_type(int type, int s){ + double tp[129]; + double sp[129]; + double spj[129]; +- struct prefix temps[65]; ++ struct prefix temps[N]; + int tlen, slen; + int r, start, end; + int delta; + + // printf("this = 0x%08x\n",this); + +- for (int i=0; i<65; i++) { ++ for (int i=0; i 64){ ++ if (tlen < 0 || tlen > 256){ + printf("Error 1 : tlen is out of range, tlen = %d\n",tlen); + exit(1); + } +@@ -208,7 +208,7 @@ void PrefixList::smooth_type(int type, int s){ + // Spread spike in source distribution for total distribution i + skj = ((int)floor((double)s/(double)2)) * 2; + binomial(skj,spj); +- for (int j = 0; j <= 32; j++){ ++ for (int j = 0; j <= 128; j++){ + // j = source length + // Find source spike + if (prefixes[type][i].sprob[j] > 0){ +@@ -221,9 +221,9 @@ void PrefixList::smooth_type(int type, int s){ + slen = j - skj/2; bdist = 0; + } + // printf("slen = %d, bdist = %d\n",slen,bdist); +- while (slen <= 32 && bdist <= skj) { ++ while (slen <= 128 && bdist <= skj) { + +- if (i < 0 || i > 64 || slen < 0 || slen > 32){ ++ if (i < 0 || i > 256 || slen < 0 || slen > 128){ + printf("Error 2: i or slen is out of range, i = %d, slen = %d\n",i,slen); + exit(1); + } +@@ -242,7 +242,7 @@ void PrefixList::smooth_type(int type, int s){ + for (int m = 1; m <= s; m++) { + // compute total length point + r = i - m; +- if (0 <= r && r <= 64) { ++ if (0 <= r && r <= 256) { + // set start, end points for source distribution + start = j - m; + end = j; +@@ -268,9 +268,9 @@ void PrefixList::smooth_type(int type, int s){ + bdist = 0; + } + // printf("start = %d, bdist = %d\n",start,bdist); +- while (start <= 32 && bdist <= sk) { ++ while (start <= 128 && bdist <= sk) { + +- if (r < 0 || r > 64 || start < 0 || start > 32){ ++ if (r < 0 || r > 256 || start < 0 || start > 128){ + printf("Error 3: r or start is out of range, r = %d, start = %d\n",r,start); + exit(1); + } +@@ -290,7 +290,7 @@ void PrefixList::smooth_type(int type, int s){ + for (int m = 1; m <= s; m++) { + // compute total length point + r = i + m; +- if (0 <= r && r <= 64) { ++ if (0 <= r && r <= 256) { + // set start, end points for source distribution + start = j; + end = j + m; +@@ -315,9 +315,9 @@ void PrefixList::smooth_type(int type, int s){ + bdist = 0; + } + // printf("start = %d, bdist = %d\n",start,bdist); +- while (start <= 32 && bdist <= sk) { ++ while (start <= 128 && bdist <= sk) { + +- if (r < 0 || r > 64 || start < 0 || start > 32){ ++ if (r < 0 || r > 256 || start < 0 || start > 128){ + printf("Error 4: r or start is out of range, start = %d, q = %d\n",r,start); + exit(1); + } +@@ -345,25 +345,25 @@ void PrefixList::smooth_type(int type, int s){ + temps[i].prob = temps[i].prob / totw; + if (temps[i].prob > 0) { + // Truncate source distribution +- if (i < 32) { +- for (int j = i + 1; j <= 32; j++) temps[i].sprob[j] = 0; ++ if (i < 128) { ++ for (int j = i + 1; j <= 128; j++) temps[i].sprob[j] = 0; + } +- else if (i > 32) { +- for (int j = 0; j < i - 32; j++) temps[i].sprob[j] = 0; ++ else if (i > 128) { ++ for (int j = 0; j < i - 128; j++) temps[i].sprob[j] = 0; + } + // Normalize source distribution + tots = 0; +- for (int j = 0; j <= 32; j++) tots += temps[i].sprob[j]; +- for (int j = 0; j <= 32; j++) temps[i].sprob[j] = temps[i].sprob[j] / tots; ++ for (int j = 0; j <= 128; j++) tots += temps[i].sprob[j]; ++ for (int j = 0; j <= 128; j++) temps[i].sprob[j] = temps[i].sprob[j] / tots; + } + } + // Apply adjustments to prefixes data structure + for (int i = 0; i < N; i++) { + prefixes[type][i].prob = temps[i].prob; + if (i == N-1) prefixes[type][i].prob = 1; +- for (int j = 0; j < 33; j++) { ++ for (int j = 0; j < 129; j++) { + prefixes[type][i].sprob[j] = temps[i].sprob[j]; +- if (j == 32) prefixes[type][i].sprob[j] = 1; ++ if (j == 128) prefixes[type][i].sprob[j] = 1; + } + } + } +@@ -382,7 +382,7 @@ struct ppair PrefixList::choose_prefix(int type, float rs, float rt) { + for (int i = 0; (i < N && done == 0); i++) { + // printf("rt = %.6f, prefixes[type][%d].prob = %.6f\n",rt,i,prefixes[type][i].prob); + if (rt <= prefixes[type][i].prob) { +- for (int j = 0; (j < 33 && done == 0); j++) { ++ for (int j = 0; (j < 129 && done == 0); j++) { + // printf("rs = %.6f, prefixes[type][%d].sprob[%d] = %.6f\n",rs,i,j,prefixes[type][i].sprob[j]); + if (rs <= prefixes[type][i].sprob[j]){ + pair.slen = j; +@@ -407,7 +407,7 @@ void PrefixList::build_cdist() { + tp = prefixes[type][i].prob; + // Cummulative source distribution + sp = 0; +- for (int j = 0; j < 33; j++){ ++ for (int j = 0; j < 129; j++){ + prefixes[type][i].sprob[j] += sp; + sp = prefixes[type][i].sprob[j]; + } +@@ -421,7 +421,7 @@ void PrefixList::print(int type, FILE *fp) { + for (int i = 0; i < N; i++){ + if (prefixes[type][i].prob != 0) { + fprintf(fp,"%d,%.8f",i,prefixes[type][i].prob); +- for (int j = 0; j <= 32; j++) { ++ for (int j = 0; j <= 128; j++) { + if (prefixes[type][i].sprob[j] != 0) { + fprintf(fp,"\t%d,%.8f",j,prefixes[type][i].sprob[j]); + } +diff --git a/PrefixList.h b/PrefixList.h +index 2d39529..1df63a2 100644 +--- a/PrefixList.h ++++ b/PrefixList.h +@@ -15,7 +15,7 @@ + + struct prefix { + float prob; +- float sprob[33]; ++ float sprob[129]; + }; + + class PrefixList { +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { +diff --git a/README b/README +index 116aac2..f104e85 100644 +--- a/README ++++ b/README +@@ -75,17 +75,17 @@ PPC + 10 AR/WC source port arbitrary range, destination port wildcard + 11 HI/AR source port [1024:65535], destination port arbitrary range + 12 AR/HI source port arbitrary range, destination port [1024:65535] +-13 LO/AR source port [0:1023], destination port arbitrary range +-14 AR/LO source port arbitrary range, destination port [0:1023] +-15 AR/AR source port arbitrary range, destination port arbitrary range +-16 WC/EM source port wildcard, destination port exact match +-17 EM/WC source port exact match, destination port wildcard +-18 HI/EM source port [1024:65535], destination port exact match +-19 EM/HI source port exact match, destination port [1024:65535] +-20 LO/EM source port [0:1023], destination port exact match +-21 EM/LO source port exact match, destination port [0:1023] ++13 WC/EM source port wildcard, destination port exact match ++14 EM/WC source port exact match, destination port wildcard ++15 HI/EM source port [1024:65535], destination port exact match ++16 EM/HI source port exact match, destination port [1024:65535] ++17 LO/AR source port [0:1023], destination port arbitrary range ++18 AR/LO source port arbitraty range, destination port [0:1023] ++19 LO/EM source port [0:1023], destination port exact match ++20 EM/LO source port exact match, destination port [0:1023] ++21 AR/AR source port arbitraty range, destination port arbitrary range + 22 AR/EM source port arbitrary range, destination port exact match +-23 EM/AR source port exact match, destination port exact match arbitrary range ++23 EM/AR source port exact match, destination port arbitrary range + 24 EM/EM source port exact match, destination port exact match + + -flags +diff --git a/TupleBST.cc b/TupleBST.cc +index 9163d9b..911f1d5 100644 +--- a/TupleBST.cc ++++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ +@@ -34,7 +34,7 @@ void TupleBST::cleanup(TupleBST_item* node){ + + int TupleBST::scope(FiveTuple* ftuple){ + double scope5d; +- scope5d = (32 - ftuple->sa_len) + (32 - ftuple->da_len) + (log(ftuple->sp_wid)/log(2)) + (log(ftuple->dp_wid)/log(2)) + (8*(1 - ftuple->prot)) + (1 - ftuple->flag); ++ scope5d = (128 - ftuple->sa_len) + (128 - ftuple->da_len) + (log(ftuple->sp_wid)/log(2)) + (log(ftuple->dp_wid)/log(2)) + (8*(1 - ftuple->prot)) + (1 - ftuple->flag); + return (int)scope5d; + } + +diff --git a/custom_db.cc b/custom_db.cc +index 6f8d193..7515336 100644 +--- a/custom_db.cc ++++ b/custom_db.cc +@@ -20,15 +20,61 @@ + #include "redundant_filter_check.h" + #include "TupleBST.h" + #include "custom_db.h" ++#include ++#include "ip_prefix.h" ++#include "trie.h" ++#include "filter_graph.h" ++ ++namespace ip = std::experimental::net::ip; ++ ++ ++/* ++ * Transforms a pruned source/destination trie into a set of edges from/to the ++ * 's'/'t' node in the filter graph. ++ * The given trie is recursively traversed. When the traversed node is a prefix ++ * node, adding of the corresponding edge from/to the 's'/'t' node of the ++ * filter graph is triggered. Weight of the added edge is set according to the ++ * number of prefixes represented by the current prefix node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A pointer to the current trie node. ++ * @param src_trie The trie node referenced by parameter node belongs to ++ * the source trie (TRUE) or the destination trie (FALSE). ++ * @param prefix_str The prefix represented by the current node encoded as a ++ * string of bit values. ++ * @param graph A pointer to the filter graph object. ++ */ ++void trie_to_graph(const trie_node* node, bool src_trie, string prefix_str, Filter_graph* graph) { ++ if (node != NULL) { // non-empty subtree ++ int prefix_count = node->prefixes; ++ if (prefix_count > 0) { // prefix node ++ // add current prefix to the filter graph, either as "s_prefix" or as "t_prefix" ++ IP_prefix prefix(prefix_str, true); ++ if (src_trie) { ++ graph->add_s_prefix(prefix, prefix_count); ++ } else { ++ graph->add_t_prefix(prefix, prefix_count); ++ } ++ } ++ // call this function on both zero and one subtrees ++ trie_to_graph(node->zero, src_trie, prefix_str + "0", graph); ++ trie_to_graph(node->one, src_trie, prefix_str + "1", graph); ++ } else { // empty subtree ++ return; ++ } ++} // end trie_to_graph() + + + int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ + ++ // generate 100 times more filters (because of successive trie pruning) ++ int temp_num_filters = num_filters * 100; ++ + printf("Initializing data structures...\n"); + // Read in scale + int scale = read_scale(fp_in); + // printf("scale = %d\n",scale); +- float scale_factor = (float)num_filters/(float)scale; ++ float scale_factor = (float)temp_num_filters/(float)scale; + // printf("scale_factor = %.4f\n",scale); + + // Read protocol parameters, initialize data structure +@@ -80,7 +126,10 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + // Temporary filter + // struct filter temp_filter; +- struct filter *temp_filters = new struct filter[num_filters+1]; ++ struct filter *temp_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -89,7 +138,7 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf("Creating application specifications...\n"); + + // For all filters: +- for (int i = 1; i <= num_filters; i++){ ++ for (int i = 1; i <= temp_num_filters; i++){ + // Select a protocol via random number + p = drand48(); + temp_filters[i].prot_num = protL->choose_prot((float)p); +@@ -143,6 +192,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -180,10 +231,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + } + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); + (*Stree).build_tree(Flist,temp_filters); +- delete(Stree); + /* + printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- for (int i = 1; i <= num_filters; i++) ++ for (int i = 1; i <= temp_num_filters; i++) + printf("filter[%d].sa = %u/%d\n",i,temp_filters[i].sa,temp_filters[i].sa_len); + */ + printf(" \tdone\n"); +@@ -203,13 +253,245 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + + (*Dtree).build_tree(Flist,temp_filters); + // printf("Flist = "); (*Flist).print(stdout); printf("\n"); +- delete(Dtree); + printf(" \tdone\n"); + + delete(Flist); + ++ ++// **************************************************************************** ++// START of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ // transform filter set into filter graph and insert source/destination ++ // prefixes of filters into corresponding tries ++ Filter_graph graph; ++ Trie src_trie; ++ Trie dst_trie; ++ for (int i = 1; i <= temp_num_filters; i++) { ++ graph.add_filter(&(temp_filters[i])); ++ src_trie.insert(IP_prefix(temp_filters[i].sa, temp_filters[i].sa_len)); ++ dst_trie.insert(IP_prefix(temp_filters[i].da, temp_filters[i].da_len)); ++ } ++ ++ // get statistics of source and destination tries ++ trie_stats src_trie_stats, dst_trie_stats; ++ src_trie.get_stats(src_trie_stats); ++ dst_trie.get_stats(dst_trie_stats); ++ ++ // initialize data structures for trie-related distributions ++ vector src_prefixes(129,0); ++ vector src_one_child(129,0); ++ vector src_two_children(129,0); ++ vector src_skew(129,0); ++ vector dst_prefixes(129,0); ++ vector dst_one_child(129,0); ++ vector dst_two_children(129,0); ++ vector dst_skew(129,0); ++ ++ // get source and destination prefix length distributions ++ // Use prefix length distributions from already generated source and ++ // destination prefix sets as ClassBench-generated rule sets follow them ++ // quite precisely. ++ for (int i = 0; i < 129; i++) { ++ src_prefixes[i] = (float)src_trie_stats.classbench.prefix_lengths[i] / ++ (float)src_trie_stats.classbench.prefixes; ++ dst_prefixes[i] = (float)dst_trie_stats.classbench.prefix_lengths[i] / ++ (float)dst_trie_stats.classbench.prefixes; ++ } ++ ++ // get other src distributions ++ // Copy the values that were already read from the parameter file into Stree. ++ for (int i = 0; i < 129; i++) { ++ src_one_child[i] = Stree->get_p1child()[i]; ++ src_two_children[i] = Stree->get_p2child()[i]; ++ src_skew[i] = Stree->get_skew()[i]; ++ } ++ delete(Stree); ++ ++ // get other dst distributions ++ // Copy the values that were already read from the parameter file into Dtree. ++ for (int i = 0; i < 129; i++) { ++ dst_one_child[i] = Dtree->get_p1child()[i]; ++ dst_two_children[i] = Dtree->get_p2child()[i]; ++ dst_skew[i] = Dtree->get_skew()[i]; ++ } ++ delete(Dtree); ++ ++ // prune source and destination tries to 1/100 of the original prefix sets ++ src_trie.prune(num_filters, src_prefixes, src_one_child, ++ src_two_children, src_skew); ++ dst_trie.prune(num_filters, dst_prefixes, dst_one_child, ++ dst_two_children, dst_skew); ++ ++ // extend filter graph according to pruned tries ++ trie_to_graph(src_trie.get_root(), true, "", &graph); ++ trie_to_graph(dst_trie.get_root(), false, "", &graph); ++ ++ // modify the filter graph to conform with the flow network specification ++ graph.to_flow_network(); ++ ++ // compute maximum flow for the current flow network ++ int max_flow = graph.max_flow(); ++ ++ // auxiliary variables for construction of the set of pruned filters ++ struct filter* pruned_filters = new struct filter[temp_num_filters+1]; ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ pruned_filters[i].num_ext_field = 0; ++ } ++ int pruned_filters_i = 1; ++ ++ /* ++ * 1st phase of construction of the set of pruned filters ++ */ ++ // iterate over all filters ++ const node_list_item* node; ++ node = graph.get_src_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ filter_list_item* filter = neighbour->filters; ++ for (int i = 0; i < neighbour->flow; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ // copy filters from the maximum flow to the pruned_filters array ++ copy_filter(pruned_filters[pruned_filters_i], *(filter->filter)); ++ pruned_filters_i++; ++ filter = filter->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ neighbour = neighbour->next; ++ } ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ node = node->next; ++ } ++ ++ /* ++ * 2nd phase of construction of the set of pruned filters ++ */ ++ // auxiliary variables for looking for not fully utilized source prefixes ++ neighbour_list_item* s_neighbour = (graph.get_s_node() != NULL) ? ++ graph.get_s_node()->neighbours : NULL; ++ // iterate over all destination prefixes ++ node = graph.get_dst_nodes(); ++ while (node != NULL) { ++ neighbour_list_item* neighbour = node->neighbours; ++ if (neighbour != NULL) { ++ int free_weight = neighbour->weight - neighbour->flow; ++ // auxiliary variables for looking for not fully utilized filters with ++ // current destination prefix ++ const node_list_item* src_node = graph.get_src_nodes(); ++ neighbour_list_item* src_neighbour; ++ filter_list_item* src_filter; ++ int src_filter_index = 0; ++ // for each not fully utilized destination prefix ++ for (int i = 0; i < free_weight; i++) { ++ // leave the cycle if enough filters have been selected ++ if (pruned_filters_i == num_filters+1) { ++ break; ++ } ++ ++// FILTERS start -------------------------------------------------------------- ++ ++ // iterate over all filters with current destination prefix ++ while (src_node != NULL) { ++ src_neighbour = src_node->neighbours; ++ while (src_neighbour != NULL) { ++ if (src_neighbour->node->prefix == node->prefix) { ++ src_filter = src_neighbour->filters; ++ // skip over all filters from the maximum flow ++ for (; ++ src_filter_index < src_neighbour->flow; ++ src_filter_index++) { ++ src_filter = src_filter->next; ++ } ++ if (src_filter != NULL) {// this filter is not fully ++ // utilized ++ ++// SOURCE PREFIXES start ------------------------------------------------------ ++ ++ // find the first not fully utilized source prefix ++ while (s_neighbour != NULL) { ++ // if this source prefix is not fully utilized ++ if (s_neighbour->flow < s_neighbour->weight) { ++ // create local copy of the selected filter and ++ // modify its source prefix ++ struct filter pruned_filter; ++ copy_filter(pruned_filter, *(src_filter->filter)); ++ pruned_filter.sa = ++ s_neighbour->node->prefix.get_prefix_uint128_t(); ++ pruned_filter.sa_len = ++ s_neighbour->node->prefix.get_length(); ++ // inset the filter into the pruned_filters array ++ pruned_filters[pruned_filters_i++] = ++ pruned_filter; ++ // increment flow value through used edges ++ s_neighbour->flow++; ++ src_neighbour->flow++; ++ neighbour->flow++; ++ // terminate looking for the next not fully ++ // utilized source prefix ++ break; ++ } ++ s_neighbour = s_neighbour->next; ++ } ++ // always terminate looking for not fully utilized ++ // filters because of the following reasons: ++ // * if not fully utilized source prefix was found, ++ // move to the next not fully utilized destination ++ // prefix ++ // * if not fully utilized source prefix was not ++ // found, terminate inserting filters into the ++ // pruned_filters array at all ++ break; ++ ++// SOURCE PREFIES end --------------------------------------------------------- ++ ++ } else { // this filter is fully utilized ++ src_filter_index = 0; ++ } ++ } ++ src_neighbour = src_neighbour->next; ++ } ++ // if the previous cycle was broken, break also this cycle ++ // (because of the same reasons) ++ if (src_neighbour != NULL) { ++ break; ++ } ++ src_node = src_node->next; ++ } ++ // if either all filters or prefixes are fully utilized, terminate ++ // looking for not fully utilized filters ++ if ((src_node == NULL) || (s_neighbour == NULL)) { ++ break; ++ } ++ ++// FILTERS end ---------------------------------------------------------------- ++ ++ } ++ } ++ // if all source prefixes are fully utilized or enough filters have been ++ // selected, terminate looking for not fully utilized destination prefixes ++ if ((s_neighbour == NULL) || (pruned_filters_i == num_filters+1)) { ++ break; ++ } ++ node = node->next; ++ } ++ ++// **************************************************************************** ++// END of IMPROVEMENTS implemented in ClassBench-ng ++// **************************************************************************** ++ ++ + printf("Removing redundant filters and ordering nested filters...\n"); +- int filter_cnt = remove_redundant_filters(num_filters,filters,temp_filters); ++ int filter_cnt = remove_redundant_filters(pruned_filters_i-1,filters,pruned_filters); + printf(" \tdone\n"); + + // Resolve conflicts, throw away filters if necessary +@@ -219,7 +501,16 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < temp_num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ if (pruned_filters[i].num_ext_field > 0) { ++ delete[] (pruned_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); ++ delete[] (pruned_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +@@ -464,33 +755,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po + } + + void fprint_filter(FILE *fp, struct filter *filt){ +- int addr[4]; +- unsigned temp; ++ uint128_t temp; + + // Print new filter character + fprintf(fp,"@"); +- // Print source address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = filt->sa; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- filt->sa_len); +- // Print destination address +- addr[0] = addr[1] = addr[2] = addr[3] = 0; +- temp = 0; +- temp = filt->da; +- addr[0] = (temp >> 24); +- addr[1] = ((temp << 8) >> 24); +- addr[2] = ((temp << 16) >> 24); +- addr[3] = ((temp << 24) >> 24); +- fprintf(fp, "%d.%d.%d.%d/%d\t", +- addr[0], addr[1], addr[2], addr[3], +- filt->da_len); ++ // Print source/destination address ++ if (ADDRLEN == 32) { // IPv4 ++ // Source address ++ temp = filt->sa >> 96; ++ ip::address_v4 src_addr(temp); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), (filt->sa_len < 32) ? filt->sa_len : 32); ++ // Destination address ++ temp = filt->da >> 96; ++ ip::address_v4 dst_addr(temp); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), (filt->da_len < 32) ? filt->da_len : 32); ++ } else { // IPv6 ++ // Source address ++ temp = filt->sa; ++ const ip::address_v6::bytes_type src_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 src_addr(src_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", src_addr.to_string().c_str(), filt->sa_len); ++ // Destination address ++ temp = filt->da; ++ const ip::address_v6::bytes_type dst_temp_bytes_type( ++ (unsigned char) (temp.upper() >> 56), ++ (unsigned char) (temp.upper() >> 48), ++ (unsigned char) (temp.upper() >> 40), ++ (unsigned char) (temp.upper() >> 32), ++ (unsigned char) (temp.upper() >> 24), ++ (unsigned char) (temp.upper() >> 16), ++ (unsigned char) (temp.upper() >> 8), ++ (unsigned char) temp.upper(), ++ (unsigned char) (temp.lower() >> 56), ++ (unsigned char) (temp.lower() >> 48), ++ (unsigned char) (temp.lower() >> 40), ++ (unsigned char) (temp.lower() >> 32), ++ (unsigned char) (temp.lower() >> 24), ++ (unsigned char) (temp.lower() >> 16), ++ (unsigned char) (temp.lower() >> 8), ++ (unsigned char) temp.lower()); ++ ip::address_v6 dst_addr(dst_temp_bytes_type); ++ fprintf(fp, "%s/%d\t", dst_addr.to_string().c_str(), filt->da_len); ++ } + // Print source port + fprintf(fp, "%d : %d\t", + filt->sp[0], filt->sp[1]); +diff --git a/db_generator.cc b/db_generator.cc +index 3344759..afa53fb 100644 +--- a/db_generator.cc ++++ b/db_generator.cc +@@ -15,6 +15,9 @@ + #include "custom_db.h" + #include "sys/time.h" + ++// IP address length in bits (global variable) ++int ADDRLEN = 32; ++ + main(int argc, char *argv[]) + { + char filename[1024]; +@@ -24,19 +27,20 @@ main(int argc, char *argv[]) + FILE *fp_std; // output file pointer for standard form filter file + + int num_filters = 0; // number of filters +- ++ + int smoothness = 0; // precision of database replication + float addr_scope = 0; // adjustment to average address scope + float port_scope = 0; // adjustment to average port scope + + // Check for correct number of input arguments + if (argc > 8 || argc <= 1){ +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"db_generator is a synthetic filter database generator.\n"); +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"\t -h displays help menu\n"); + fprintf(stderr,"\t -r generates a random database\n"); + fprintf(stderr,"\t -b turns on address prefix scaling with database size; note that this alters the skew distribution in the parameter file\n"); ++ fprintf(stderr,"\t -6 generates a database with IPv6 5-tuples\n"); + fprintf(stderr,"\t -c generates a custom database using an input parameter file\n"); + fprintf(stderr,"\t is a parameter [0:64] that injects structured randomness\n"); + fprintf(stderr,"\t
is a parameter [-1.0:1.0] that adjusts the average scope of the address prefix pairs\n"); +@@ -65,12 +69,16 @@ main(int argc, char *argv[]) + case 'b': + branch = 1; + break; ++ case '6': ++ ADDRLEN = 128; ++ break; + case 'h': + fprintf(stderr,"db_generator is a synthetic filter database generator.\n"); +- fprintf(stderr,"Usage: db_generator -hrb (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + fprintf(stderr,"\t -h displays help menu\n"); + fprintf(stderr,"\t -r generates a random database\n"); + fprintf(stderr,"\t -b turns on address prefix scaling with database size; note that this alters the skew distribution in the parameter file\n"); ++ fprintf(stderr,"\t -6 generates a database with IPv6 5-tuples\n"); + fprintf(stderr,"\t -c generates a custom database using an input parameter file\n"); + fprintf(stderr,"\t is a parameter [0:64] that injects structured randomness\n"); + fprintf(stderr,"\t
is a parameter [-1.0:1.0] that adjusts the average scope of the address prefixe pairs\n"); +@@ -87,7 +95,7 @@ main(int argc, char *argv[]) + } + } + } +- ++ + if (random == 1 && argc == 2){ + num_filters = atoi(argv[0]); + strcpy(filename,argv[1]); +@@ -99,21 +107,21 @@ main(int argc, char *argv[]) + // printf("smoothness = %d\n",smoothness); + if (smoothness < 0 || smoothness > 64) { + fprintf(stderr,"Error smoothness must be a value in the range [0:64]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + sscanf(argv[3],"%f",&addr_scope); + // printf("addr_scope = %.4f\n",addr_scope); + if (addr_scope < -1 || addr_scope > 1) { + fprintf(stderr,"Error address scope must be a value in the range [-1:1]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + sscanf(argv[4],"%f",&port_scope); + // printf("addr_scope = %.4f\n",port_scope); + if (port_scope < -1 || port_scope > 1) { + fprintf(stderr,"Error port scope must be a value in the range [-1:1]\n"); +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + strcpy(filename,argv[5]); +@@ -121,7 +129,7 @@ main(int argc, char *argv[]) + fp_in = fopen(in_filename,"r"); + if (fp_in == NULL) {fprintf(stderr,"ERROR: cannot open seed file %s\n",in_filename); exit(1);} + } else { +- fprintf(stderr,"Usage: db_generator -hr (-c )
\n"); ++ fprintf(stderr,"Usage: db_generator -hrb6 (-c )
\n"); + exit(1); + } + +diff --git a/dbintree.cc b/dbintree.cc +index 9274710..9a53299 100644 +--- a/dbintree.cc ++++ b/dbintree.cc +@@ -13,13 +13,13 @@ + + dbintree::dbintree() { + // Initialize to graph with N vertices and no edges. +- skew = new float[33]; +- corr = new float[33]; +- p1child = new float[33]; +- p2child = new float[33]; ++ skew = new float[129]; ++ corr = new float[129]; ++ p1child = new float[129]; ++ p2child = new float[129]; + num_tnodes = 0; + root = NULL; +- for (int u = 0; u < 33; u++) { ++ for (int u = 0; u < 129; u++) { + skew[u] = 0; + corr[u] = 0; + p1child[u] = 0; +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +@@ -99,13 +100,13 @@ void dbintree::read_skew(FILE* fp_in){ + // printf("matches = %d\n",matches); + // printf("level = %d, skew = %.4f\n",level,skew); + if (matches == 4) { +- if (level <= 32) { ++ if (level <= 128) { + p1child[level] = p1_t; + p2child[level] = p2_t; + skew[level] = f_skew; + } + else { +- fprintf(stderr,"Level for destination address skew is greater than 32.\n"); ++ fprintf(stderr,"Level for destination address skew is greater than 128.\n"); + exit(1); + } + // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); +@@ -147,7 +148,7 @@ void dbintree::read_corr(FILE* fp_in){ + void dbintree::print_skew(FILE *fp) { + + fprintf(fp,"Level\tp1\tp2\tSkew\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", + i,p1child[i],p2child[i],skew[i]); + } +@@ -157,14 +158,14 @@ void dbintree::print_skew(FILE *fp) { + void dbintree::print_corr(FILE *fp) { + + fprintf(fp,"Level\tCorr\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\n",i,corr[i]); + } + return; + } + + void dbintree::build_tree(dlist* Flist, struct filter filters[]){ +- unsigned int addr = 0; ++ uint128_t addr = 0; + // Create copy of list + dlist *temp_list = new dlist(); + (*temp_list)=(Flist); +@@ -221,7 +222,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ + return; + } + +-void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void dbintree::add_stub(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + int lev = node->lvl; + +@@ -237,21 +238,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // printf("Flist_size = %d\n",Flist_size); + + double temp; +- unsigned int sa; ++ uint128_t sa; + +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + // Adjust addresses + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + + // Allocate temp_list's +@@ -297,7 +298,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // printf("Flist_size = %d, tempList: ",Flist_size); tempList->print(stdout); printf("\n"); + // if lev1_flag == 1, dump all lev1 filters to one side + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // printf("add_stub: Enforcing nesting limit\n"); + // Add all filters to stublist and let the finish_node process distribute them + int fptr; +@@ -331,7 +332,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + // sa_len > lvl + // Prevent prefix nesting + sa = sa << lev; +- sa = sa >> 31; ++ sa = sa >> 127; + // sa now equals next "bit" of source address + if (filters[fptr].sa_len == (lev+1)) { + // Source prefix will be exhausted at next level +@@ -407,7 +408,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str + return; + } + +-void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void dbintree::finish_node(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + int stubList_size = 0; + int lev = node->lvl; +@@ -479,20 +480,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, + + double temp; + int path; +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + + // Adjust addresses + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + + // Create an empty list +@@ -519,7 +520,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, + // If at the nesting threshold and list has more than one child, + // then split list (allocate all nodes with level == lev1 to one path) + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((templist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((templist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // Allocate nest_list + dlist *nest_list = new dlist(); + dlist *other_list = new dlist(); +diff --git a/dbintree.h b/dbintree.h +index 5509fc3..d9311b6 100644 +--- a/dbintree.h ++++ b/dbintree.h +@@ -33,10 +33,10 @@ class dbintree { + float *p1child; // probability that a node at a given level has one child + float *p2child; // probability that a node at a given level has two children + int num_tnodes; // number of tree nodes +- void add_stub(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[],int CurrNest); ++ void add_stub(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[],int CurrNest); + void add2child_stublist(struct tnode *node, int dir, int filt); + void add_node(struct tnode *prnt, int lev, int dir); +- void finish_node(struct tnode *node, unsigned int addr, dlist* Flist, struct filter filters[],int CurrNest); ++ void finish_node(struct tnode *node, uint128_t addr, dlist* Flist, struct filter filters[],int CurrNest); + int Nest; // Maximum allowed nesting + + public: dbintree(); +@@ -51,4 +51,15 @@ class dbintree { + void print_corr(FILE*); // print correlation per level + void build_tree(dlist* Flist, struct filter filters[]); + void lsort(); // sort nodes by level ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; +diff --git a/filter_graph.cc b/filter_graph.cc +new file mode 100644 +index 0000000..726869a +--- /dev/null ++++ b/filter_graph.cc +@@ -0,0 +1,785 @@ ++// filter_graph.cc: Filter_graph class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "stdinc.h" ++#include "flow_network.h" ++#include "filter_graph.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Auxiliary (non-member) functions ************************************* ++ ++ ++/* ++ * Private function that builds a flow network corresponding to the filter ++ * graph. ++ * In three iterations the function traverses all edges of the filter graph ++ * (i.e., s_node->src_nodes, src_nodes->dst_nodes, and dst_nodes->t_node edges) ++ * and constructs the flow network corresponding to this graph. Each edge of ++ * the filter graph can be represented by at most two edges of the flow ++ * network -- a forward and backward edge. Note that they are included into the ++ * flow network only if their residual capacity is greater than zero. ++ * The function expects that the input graph is already a valid flow network, ++ * i.e., it contains only one node without input edges (the 's' node) and only ++ * one node without output edges (the 't' node). ++ * @param network Reference to the (most probably empty) flow network object. ++ * @param graph Pointer to the constant filter graph object. ++ */ ++void build_flow_network(Flow_network& network, const Filter_graph* graph) { ++ // declatarion of "phase" variables ++ const node_list_item* list; ++ int src_list; ++ int dst_list; ++ ++ // iteration through three phases ++ for (int i = 0; i < 3; i++) { ++ // setting of phase variables ++ switch (i) { ++ case 0: // edges from the 's' node to destination nodes ++ list = graph->get_s_node(); ++ src_list = 0; ++ dst_list = 1; ++ break; ++ case 1: // edges from source nodes to destination nodes ++ list = graph->get_src_nodes(); ++ src_list = 1; ++ dst_list = 2; ++ break; ++ case 2: // edges from destination nodes to the 'd' node ++ list = graph->get_dst_nodes(); ++ src_list = 2; ++ dst_list = 3; ++ break; ++ } ++ ++ // iteration over all nodes in the list ++ while (list != NULL) { ++ neighbour_list_item* neighbour = list->neighbours; ++ // iteration over all neighbours (i.e., edges of the filter graph) ++ while (neighbour != NULL) { ++ // compute residual capacity of forward and backward edges ++ int capacity_forward = neighbour->weight - neighbour->flow; ++ int capacity_backward = neighbour->flow; ++ // insert the forward edge, if it has capacity > 0 ++ if (capacity_forward > 0) { ++ network.add_edge(list->prefix, src_list, ++ neighbour->node->prefix, dst_list, ++ neighbour, true, capacity_forward); ++ } ++ // insert the backward edge, if it has capacity > 0 ++ if (capacity_backward > 0) { ++ network.add_edge(neighbour->node->prefix, dst_list, ++ list->prefix, src_list, ++ neighbour, false, capacity_backward); ++ } ++ // move to the next edge ++ neighbour = neighbour->next; ++ } ++ // move to the next node ++ list = list->next; ++ } ++ } ++} // end build_flow_network() ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++node_list_item* Filter_graph::copy_node_list(const node_list_item* orig) { ++ // initialize pointer to copied node list ++ node_list_item* result = (orig == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // node list level of copying ++ node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->pruned = orig->pruned; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new node_list_item; ++ ++ // neighbour list level of copying ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->weight = orig_neighbours->weight; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->filters = (orig_neighbours->filters == NULL) ? ++ NULL : ++ new filter_list_item; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new neighbour_list_item; ++ ++ // filter list level of copying ++ filter_list_item* orig_filters = orig_neighbours->filters; ++ filter_list_item* copy_filters = copy_neighbours->filters; ++ while (orig_filters != NULL) { ++ // list item members initialization ++ copy_filters->filter = orig_filters->filter; ++ copy_filters->next = (orig_filters->next == NULL) ? ++ NULL : ++ new filter_list_item; ++ // move to the next item of filter list ++ copy_filters = copy_filters->next; ++ orig_filters = orig_filters->next; ++ } ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Filter_graph::remove_node_list(node_list_item** list) { ++ // traverse all nodes ++ while ((*list) != NULL) { ++ // get pointer to the first node ++ node_list_item* first_node = *list; ++ ++ // correctly deallocate its whole neighbour list ++ remove_neighbour_list(&(first_node->neighbours)); ++ ++ // move to the next node list item and deallocate the current one ++ node_list_item* next_node = first_node->next; ++ delete first_node; ++ *list = next_node; ++ } ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ */ ++void Filter_graph::remove_neighbour_list(neighbour_list_item** list) { ++ // traverse all neighbours ++ while ((*list) != NULL) { ++ // get pointer to the first neighbour ++ neighbour_list_item* first_neighbour = *list; ++ ++ // correctly deallocate it whole filter list ++ remove_filter_list(&(first_neighbour->filters)); ++ ++ // move to the next neighbour list item and deallocate the current one ++ neighbour_list_item* next_neighbour = first_neighbour->next; ++ delete first_neighbour; ++ *list = next_neighbour; ++ } ++} // end remove_neighbour_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole filter list. ++ */ ++void Filter_graph::remove_filter_list(filter_list_item** list) { ++ // traverse all filters ++ while ((*list) != NULL) { ++ // get pointer to the first filter ++ filter_list_item* first_filter = *list; ++ ++ // move to the next filter list item and deallocate the current one ++ filter_list_item* next_filter = first_filter->next; ++ delete first_filter; ++ *list = next_filter; ++ } ++} // end remove_filter_list() ++ ++ ++/* ++ * Private static function that sets correct values of neighbour node pointers, ++ * which cannot be correctly initialized during copying. ++ */ ++void Filter_graph::set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst) { ++ // traverse all nodes ++ while (orig != NULL) { ++ neighbour_list_item* orig_neighbours = orig->neighbours; ++ neighbour_list_item* src_neighbours = src->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct neighbour node pointer ++ src_neighbours->node = find_node(orig_neighbours->node->prefix, dst); ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ src_neighbours = src_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ src = src->next; ++ } ++ ++ return; ++} // end set_neighbour_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++node_list_item* Filter_graph::find_node(const IP_prefix& prefix, ++ node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++neighbour_list_item* Filter_graph::find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ */ ++filter_list_item* Filter_graph::find_filter(const struct filter* filter, ++ filter_list_item* list) { ++ // traverse all filter nodes ++ while (list != NULL) { ++ if (list->filter == filter) { ++ // corresponding filter node - return pointer to it ++ return list; ++ } else { ++ // filter node pointing to different filter - move to the next item of ++ // filter list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding filter node was not found ++ return NULL; ++} // end find_filter() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Filter_graph::insert_node(const IP_prefix& prefix, ++ node_list_item** list) { ++ // allocate and initialize new prefix node ++ node_list_item* node = new node_list_item; ++ node->prefix = prefix; ++ node->pruned = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node corresponding to the ++ * given prefix node at the beginning of the given list of neighbour nodes. ++ */ ++void Filter_graph::insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ neighbour_list_item* node = new neighbour_list_item; ++ node->node = neighbour; ++ node->weight = 0; ++ node->flow = 0; ++ node->filters = NULL; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that inserts a filter node pointing to the given ++ * filter at the beginning of the given list of filter nodes. ++ */ ++void Filter_graph::insert_filter(const struct filter* filter, ++ filter_list_item** list) { ++ // allocate and initialize new filter node ++ filter_list_item* node = new filter_list_item; ++ node->filter = filter; ++ ++ // insert new filter node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_filter() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ */ ++void Filter_graph::print_node_list(const node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> " << neighbours->node->prefix.get_prefix() << "/" ++ << neighbours->node->prefix.get_length() << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->weight ++ << ")" << endl; ++ filter_list_item* filters = neighbours->filters; ++ while (filters != NULL) { ++ // print filter list items ++ cout << "| | +-> " << filters->filter->sp[0] << ":" ++ << filters->filter->sp[1] << " " ++ << filters->filter->dp[0] << ":" ++ << filters->filter->dp[1] << " " ++ << filters->filter->prot_num << endl; ++ // move to the next filter ++ filters = filters->next; ++ } ++ // moce tothe next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++/* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ */ ++void Filter_graph::remove_and_reset() { ++ for (int i = 0; i < 4; i++) { ++ // select the correct node list for iteration ++ node_list_item** node_ptr; ++ switch (i) { ++ case 0: ++ node_ptr = &s_node; ++ break; ++ case 1: ++ node_ptr = &src_nodes; ++ break; ++ case 2: ++ node_ptr = &dst_nodes; ++ break; ++ case 3: ++ node_ptr = &t_node; ++ break; ++ } ++ ++ // iterate over all nodes in the list ++ while ((*node_ptr) != NULL) { ++ node_list_item* node = *node_ptr; ++ if (node->pruned == false) { // remove the non-pruned node ++ (*node_ptr) = node->next; ++ delete node; ++ } else { // reset the "pruned" flag of the pruned node ++ node->pruned = false; ++ node_ptr = &(node->next); ++ } ++ } ++ } ++} // end remove_and_reset() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Filter_graph::Filter_graph() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Filter_graph() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Filter_graph::Filter_graph(const Filter_graph& orig) { ++ // acquire members of the original object ++ const node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const node_list_item* orig_s_node = orig.get_s_node(); ++ const node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(orig_t_node, t_node, NULL); ++ set_neighbour_nodes(orig_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(orig_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(orig_s_node, s_node, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Destructor. ++ */ ++Filter_graph::~Filter_graph() { ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++} // end ~Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Filter_graph& Filter_graph::operator=(const Filter_graph& copy) { ++ // destruct the original object ++ remove_node_list(&s_node); ++ remove_node_list(&src_nodes); ++ remove_node_list(&dst_nodes); ++ remove_node_list(&t_node); ++ ++ // acquire members of the copied object ++ const node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const node_list_item* copy_s_node = copy.get_s_node(); ++ const node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_neighbour_nodes(copy_t_node, t_node, NULL); ++ set_neighbour_nodes(copy_dst_nodes, dst_nodes, t_node); ++ set_neighbour_nodes(copy_src_nodes, src_nodes, dst_nodes); ++ set_neighbour_nodes(copy_s_node, s_node, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Modifies filter graph to add the specified filter into the set of filters ++ * represented by the graph. ++ */ ++void Filter_graph::add_filter(const struct filter* filter) { ++ // acquire source and destination prefixes ++ IP_prefix src_pref(filter->sa, filter->sa_len); ++ IP_prefix dst_pref(filter->da, filter->da_len); ++ ++ // find source prefix node and insert such node if it does not exist ++ node_list_item* src_node = find_node(src_pref, src_nodes); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_pref, &src_nodes); ++ src_node = src_nodes; ++ } ++ ++ // find destination prefix node and insert such node if it does not exist ++ node_list_item* dst_node = find_node(dst_pref, dst_nodes); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_pref, &dst_nodes); ++ dst_node = dst_nodes; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(dst_node, &(src_node->neighbours)); ++ neighbour = src_node->neighbours; ++ } ++ ++ // find filter node pointing to the specified filter and insert such node if ++ // it does not exist ++ filter_list_item* filter_node = find_filter(filter, neighbour->filters); ++ if (filter_node == NULL) { ++ insert_filter(filter, &(neighbour->filters)); ++ neighbour->weight += 1; ++ } ++} // end add_filter() ++ ++ ++/* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ */ ++void Filter_graph::add_s_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 's' node and allocate it if it does not exist ++ if (s_node == NULL) { ++ insert_node(IP_prefix(), &s_node); ++ s_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the source nodes list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* src_node = find_node(prefix, src_nodes); ++ ++ // find a neighbour node corresponding to the given prefix ++ neighbour_list_item* neighbour = find_neighbour(src_node, ++ s_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(src_node, &(s_node->neighbours)); ++ neighbour = s_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set source node's pruned flag to true ++ src_node->pruned = true; ++} // end add_s_prefix() ++ ++ ++/* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the given ++ * value. ++ */ ++void Filter_graph::add_t_prefix(const IP_prefix& prefix, const int weight) { ++ // check existence of the 't' node and allocate it if it does not exist ++ if (t_node == NULL) { ++ insert_node(IP_prefix(), &t_node); ++ t_node->pruned = true; ++ } ++ ++ // find a node representing the given prefix within the destination nodes ++ // list ++ // (existence of such node is not checked since it should always exist) ++ node_list_item* dst_node = find_node(prefix, dst_nodes); ++ ++ // find a neighbour node corresponding to the 't' node ++ neighbour_list_item* neighbour = find_neighbour(t_node, ++ dst_node->neighbours); ++ if (neighbour == NULL) { // the neighbour node does not exist ++ // insert the node at the beginning of the list ++ insert_neighbour(t_node, &(dst_node->neighbours)); ++ neighbour = dst_node->neighbours; ++ // set neighbour node's weight member ++ neighbour->weight = weight; ++ } else { // the neighbour node exists ++ // adjust neighbour node's weight member accordingly ++ neighbour->weight += weight; ++ } ++ ++ // set destination node's pruned flag to true ++ dst_node->pruned = true; ++} // end add_t_prefix() ++ ++ ++/* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ */ ++void Filter_graph::to_flow_network() { ++ // 1) remove filters containing at least one non-pruned prefix ++ node_list_item* node = src_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all neighbours of this node ++ remove_neighbour_list(&(node->neighbours)); ++ } else { // remove only neighbours pointing to a non-pruned node ++ neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this neighbour ++ remove_filter_list(&(neighbour->filters)); ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } else { // just move to the next neighbour ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ } ++ node = node->next; ++ } ++ ++ // 2) remove non-pruned nodes and reset the "pruned" flag of other nodes ++ remove_and_reset(); ++ ++ // 3) BFS to set the "pruned" flag of visited nodes with at least one ++ // neighbour and the 's' and 't' nodes ++ queue q; ++ q.push(s_node); ++ // do the BFS ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ node_list_item* node = q.front(); ++ q.pop(); ++ // set the "pruned" flag if the list of neighbours is non-empty ++ if (node->neighbours != NULL) { ++ node->pruned = true; ++ } ++ // insert neighbours into the queue ++ neighbour_list_item* neighbour = node->neighbours; ++ while (neighbour != NULL) { ++ q.push(neighbour->node); ++ neighbour = neighbour->next; ++ } ++ } ++ // set the "pruned" flag of the 's' and 't' nodes ++ s_node->pruned = true; ++ t_node->pruned = true; ++ ++ // 4) remove edges from the 's' node going to non-pruned nodes ++ neighbour_list_item** neighbour_ptr = &(s_node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ neighbour_list_item* neighbour = *neighbour_ptr; ++ if (neighbour->node->pruned == false) { // remove this edge ++ // there are no filters represented by edges from the 's' node ++ (*neighbour_ptr) = neighbour->next; ++ delete neighbour; ++ } else { // move to the next edge ++ neighbour_ptr = &(neighbour->next); ++ } ++ } ++ ++ // 5) remove edges to the 't' node going from non-pruned nodes ++ node = dst_nodes; ++ while (node != NULL) { ++ if (node->pruned == false) { // remove all edges going from this node ++ remove_neighbour_list(&(node->neighbours)); ++ } ++ // move to the next node ++ node = node->next; ++ } ++ ++ // 6) remove non-pruned nodes (and reset the "pruned" flag of other nodes) ++ remove_and_reset(); ++} // end to_flow_network() ++ ++ ++/* ++ * Computes maximum flow using Dinic's algorithm. ++ */ ++int Filter_graph::max_flow() { ++ int max_flow = 0; ++ int flow_inc; ++ ++ do { // iterate until the flow cannot be improved ++ // build flow network corresponding to the filter graph ++ Flow_network network; ++ build_flow_network(network, this); ++ ++ // transform the flow network into the level graph ++ network.to_level_graph(); ++ ++ // compute a blocking flow in the flow network and update the flow in the ++ // filter graph accordingly ++ flow_inc = network.find_blocking_flow(); ++ max_flow += flow_inc; ++ } while (flow_inc != 0); ++ ++ return max_flow; ++} // end max_flow() ++ ++ ++/* ++ * Prints the filter graph. ++ */ ++void Filter_graph::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/filter_graph.h b/filter_graph.h +new file mode 100644 +index 0000000..601f2cd +--- /dev/null ++++ b/filter_graph.h +@@ -0,0 +1,437 @@ ++// filter_graph.h: header file for Filter_graph class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FILTER_GRAPH_H ++#define FILTER_GRAPH_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct node_list_item node_list_item; ++typedef struct neighbour_list_item neighbour_list_item; ++typedef struct filter_list_item filter_list_item; ++ ++/* ++ * A structure representing an item in a list of graph nodes. ++ */ ++struct node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag that is utilized for "pruning" filters once the complete filter ++ // graph is constructed ++ bool pruned; ++ ++ // List of neighbours ++ neighbour_list_item* neighbours; ++ ++ // Next item in list of graph nodes ++ node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a graph node. ++ */ ++struct neighbour_list_item { ++ // Pointer to neighbour node within list of graph nodes ++ node_list_item* node; ++ ++ // Weight of filter graph's edge between neighbouring nodes ++ int weight; ++ ++ // Flow through filter graph's edge between neighbouring nodes ++ int flow; ++ ++ // List of filters that specify prefixes of neighbouring nodes ++ filter_list_item* filters; ++ ++ // Next item in list of neighbours ++ neighbour_list_item* next; ++}; ++ ++/* ++ * A Structure representing an item in a list of filters that specify prefixes ++ * of neighbouring graph nodes. ++ */ ++struct filter_list_item { ++ // Pointer to representation of filter ++ // (struct filter is defined in stdinc.h included in custom_db.cc) ++ const struct filter* filter; ++ ++ // Next item in list of filters ++ filter_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a set of filters as a filter graph -- i.e., ++ * weighted directed bipartite graph with special source (s) and terminate (t) ++ * nodes -- that is constructed according to filters' source and destination ++ * prefixes and pruned source and destination prefix tries. ++ */ ++class Filter_graph { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the filter graph. ++ */ ++ node_list_item* src_nodes; ++ node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the filter graph. ++ */ ++ node_list_item* s_node; ++ node_list_item* t_node; ++ ++ /* ++ * Private static function that creates deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as all sublists) and sets the value of their components ++ * according to this original list. The only exception is pointer to ++ * neighbour node, which is initialized to NULL (it points to different ++ * list, thus it cannot be initialized to correct value during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static node_list_item* copy_node_list(const node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given node list and all its sublists and ++ * starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to pointer to node list that is to be ++ * deallocated. ++ */ ++ static void remove_node_list(node_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole neighbour ++ * list. ++ * The function traverses the given neighbour list and all its sublists ++ * and starting from the inner-most list it deallocates all the traversed ++ * list items. ++ * @param Pointer to pointer to the neighbour list that is to be ++ * deallocated. ++ */ ++ static void remove_neighbour_list(neighbour_list_item** list); ++ ++ /* ++ * Private static function that correctly deallocates the whole filter ++ * list. ++ * The function traverses the given filter list and deallocates all the ++ * traversed list items. ++ * @param Pointer to pointer to the filter list that is to be ++ * deallocated. ++ */ ++ static void remove_filter_list(filter_list_item** list); ++ ++ /* ++ * Private static function that sets correct values of neighbour node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in orig and src ++ * node lists. For each neighbour node from orig list it looks for ++ * corresponding item in dst node list and stores pointer to this node to ++ * current item in src list. ++ * @param orig Pointer to the constant original node list. ++ * @param src Pointer to the list of source nodes (neighbour node ++ * pointers of this list are set). ++ * @param dst Pointer to the list of destination nodes (nodes of this ++ * list act as targets of neighbour node pointers within ++ * src node list). ++ */ ++ static void set_neighbour_nodes(const node_list_item* orig, ++ node_list_item* src, ++ node_list_item* dst); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of node that the ++ * function looks for in the list. ++ * @param list Pointer to list of nodes that is traversed during ++ * looking for node with the given IP prefix. ++ * @return Pointer to found node or NULL. ++ */ ++ static node_list_item* find_node(const IP_prefix& prefix, ++ node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static neighbour_list_item* find_neighbour( ++ const node_list_item* neighbour, ++ neighbour_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the filter node pointing to the ++ * specified filter in the given list of filters. ++ * @param filter Pointer to the constant filter that is referenced by ++ * the filter node the function looks for in the list. ++ * @param list Pointer to the list of filter nodes that is traversed ++ * during looking for a node pointing to the given ++ * filter. ++ * @return Pointer to the found filter node or NULL. ++ */ ++ static filter_list_item* find_filter(const struct filter* filter, ++ filter_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node corresponding to ++ * the given prefix node at the beginning of the given list of ++ * neighbour nodes. ++ * @param neighbour Pointer to a prefix node whose neighbour node is ++ * going to be inserted. ++ * @param list Pointer to pointer to the list of neighbours that ++ * is going to be extended by the inserted node. ++ */ ++ static void insert_neighbour(node_list_item* neighbour, ++ neighbour_list_item** list); ++ ++ /* ++ * Private static function that inserts a filter node pointing to the ++ * given filter at the beginning of the given list of filter nodes. ++ * @param node Pointer to the constant filter that is going to be ++ * referenced by the inserted filter node. ++ * @param list Pointer to pointer to the list of filters that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_filter(const struct filter* filter, ++ filter_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists (i.e., neighbour lists and filter lists). ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const node_list_item* nodes); ++ ++ /* ++ * Private function that removes non-pruned nodes and resets the "pruned" ++ * flag of pruned nodes of the filter graph. ++ * The function performs the specified function on all nodes of the ++ * filter graph (i.e., source and destination nodes as well as the 's' ++ * and 't' nodes). ++ * The function expects that neighbours list referenced from the ++ * non-pruned nodes have been correctly deallocated before calling this ++ * function. ++ */ ++ void remove_and_reset(); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Filter_graph(); ++ ++ /* ++ * Copy constructor. ++ * All pointers are initialized to a deep copy of corresponding members ++ * of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Filter_graph(const Filter_graph& orig); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Filter_graph(); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Filter_graph& operator= (const Filter_graph& copy); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Modifies filter graph to add the specified filter into the set of ++ * filters represented by the graph. ++ * The function searches src_nodes and dst_nodes lists for nodes ++ * representing source and destination prefixes of the given filter and ++ * inserts such nodes into these lists if they are not found. Next, the ++ * function seraches neighbours list of source prefix node for neighbour ++ * node representing destination prefix of the given filter and inserts ++ * such neighbour node into the list if it is not found. Finally, the ++ * function searches filters list of neighbouring node for pointer to the ++ * given filter and inserts such pointer into the list if it is not ++ * found. Along with inserting new filter pointer to the list, the ++ * function increments weight item of neighbouring node representation. ++ * @param filter Pointer to a constant structure representing inserted ++ * filter. ++ */ ++ void add_filter(const struct filter* filter); ++ ++ /* ++ * Adds an edge from the 's' node to a node representing the given prefix ++ * within the source nodes list and sets its weight to the given value. ++ * First of all, the function checks whether the 's' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the 's' node for a ++ * neighbour node representing the given prefix. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned source trie are ++ * added using this function. In such a case the source nodes list always ++ * contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * target node of the edge from the 's' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_s_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Adds an edge from a node representing the given prefix within the ++ * destination nodes list to the 't' node and sets its weight to the ++ * given value. ++ * First of all, the function checks whether the 't' node has already ++ * been allocated and allocates this node in case it does not yet exist. ++ * Next, the function searches the neighbours list of the node ++ * representing the given prefix within the destination nodes list for a ++ * neighbour node representing the 't' node. If such neighbour node ++ * exists, the function just adds the given weight to the current value ++ * of its weight counter. If such neighbour node does not exist, the ++ * function inserts the node into the list and sets its weight counter to ++ * the given value. The function also sets the "pruned" flag of the node ++ * representing the given prefix to true. ++ * The implementation expects that all filters have already been added to ++ * the filter graph and that only prefixes of a pruned destination trie ++ * are added using this function. In such a case the destination nodes ++ * list always contains a node representing the given prefix. ++ * @param prefix Reference to the IP_prefix object that determines a ++ * source node of the edge towards the 't' node. ++ * @param weight Weight of the newly created edge. ++ */ ++ void add_t_prefix(const IP_prefix& prefix, const int weight); ++ ++ /* ++ * Modifies the filter graph such that it conforms with the flow network ++ * specification -- i.e., it has only one node without input edges (the ++ * 's' node) and only one node without output edges (the 't' node). ++ * First of all, the function removes all edges representing filters with ++ * at least one non-pruned prefix and all nodes representing non-pruned ++ * prefixes. During this step, the "pruned" flag of the remaining nodes ++ * is also set to false. Next, the filter graph is traversed in a BFS ++ * manner and the "pruned" flag is set to true for all visited nodes with ++ * at least one input edge and one output edge. Finally, the function ++ * removes all edges going from the 's' node/to the 't' node that do not ++ * end/start in a node with the set "pruned" flag. These non-pruned nodes ++ * are also removed from the graph in this final step. ++ * The function expects that all steps of the filter graph construction ++ * (i.e., adding filters, s-prefixes, and t-prefixes) have already been ++ * performed before its invocation. ++ */ ++ void to_flow_network(); ++ ++ /* ++ * Computes maximum flow using Dinic's algorithm. ++ * The function builds a flow network corresponding to the filter graph, ++ * transforms it to a level graph and updates the flow through the filter ++ * graph according to a blocking flow through the level graph. This way ++ * the flow through the filter graph is iteratively updated until there ++ * are paths from the 's' node to the 't' node in the level graph. ++ * The flow network is represented by an object of the Flow_network, ++ * which also allows transformation into the corresponding level graph. ++ * @return The value of the maximum flow through the filter graph. ++ */ ++ int max_flow(); ++ ++ /* ++ * Prints the filter graph. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/flow_network.cc b/flow_network.cc +new file mode 100644 +index 0000000..b5523da +--- /dev/null ++++ b/flow_network.cc +@@ -0,0 +1,592 @@ ++// flow_network.cc: Flow_network class definition ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "flow_network.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions (related to filter graph) ************************** ++ ++ ++/* ++ * Private static function that creates deep copy of the original list. ++ */ ++net_node_list_item* Flow_network::copy_node_list(const net_node_list_item* orig) { ++ // initialize pointer to copied node list ++ net_node_list_item* result = (orig == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // node list level of copying ++ net_node_list_item* copy = result; ++ while (orig != NULL) { ++ // list item members initialization ++ copy->prefix = orig->prefix; ++ copy->visited = orig->visited; ++ copy->neighbours = (orig->neighbours == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ copy->next = (orig->next == NULL) ? ++ NULL : ++ new net_node_list_item; ++ ++ // neighbour list level of copying ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ while (orig_neighbours != NULL) { ++ // list item members initialization ++ copy_neighbours->src_node = copy; ++ copy_neighbours->dst_node = NULL; // cannot be initialized directly ++ // (points to different node list) ++ copy_neighbours->capacity = orig_neighbours->capacity; ++ copy_neighbours->flow = orig_neighbours->flow; ++ copy_neighbours->orig_edge = orig_neighbours->orig_edge; ++ copy_neighbours->forward_edge = orig_neighbours->forward_edge; ++ copy_neighbours->next = (orig_neighbours->next == NULL) ? ++ NULL : ++ new net_neighbour_list_item; ++ ++ // move to the next item of neighbour list ++ copy_neighbours = copy_neighbours->next; ++ orig_neighbours = orig_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ copy = copy->next; ++ orig = orig->next; ++ } ++ ++ return result; ++} // end copy_node_list() ++ ++ ++/* ++ * Private static function that correctly deallocates the whole node list. ++ */ ++void Flow_network::remove_node_list(net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ net_neighbour_list_item* neighbours = list->neighbours; ++ ++ // traverse all neighbours ++ while (neighbours != NULL) { ++ // move to the next neighbour list item and deallocate the current one ++ net_neighbour_list_item* current_neighbour = neighbours; ++ neighbours = neighbours->next; ++ delete current_neighbour; ++ } ++ ++ // move to the next node list item and deallocate the current one ++ net_node_list_item* current_node = list; ++ list = list->next; ++ delete current_node; ++ } ++ ++ return; ++} // end remove_node_list() ++ ++ ++/* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ */ ++void Flow_network::set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next) { ++ // traverse all nodes ++ while (orig != NULL) { ++ net_neighbour_list_item* orig_neighbours = orig->neighbours; ++ net_neighbour_list_item* copy_neighbours = copy->neighbours; ++ ++ // traverse all neighbours ++ while (orig_neighbours != NULL) { ++ // set correct destination node pointer ++ if (orig_neighbours->forward_edge) { // forward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, next); ++ } else { // backward edge ++ copy_neighbours->dst_node = ++ find_node(orig_neighbours->dst_node->prefix, prev); ++ } ++ ++ // move to the next item of neighbour list ++ orig_neighbours = orig_neighbours->next; ++ copy_neighbours = copy_neighbours->next; ++ } ++ ++ // move to the next item of node list ++ orig = orig->next; ++ copy = copy->next; ++ } ++ ++ return; ++} // end set_destination_nodes() ++ ++ ++/* ++ * Private static function that looks for node with the given prefix in the ++ * given list of nodes. ++ */ ++net_node_list_item* Flow_network::find_node(const IP_prefix& prefix, ++ net_node_list_item* list) { ++ // traverse all nodes ++ while (list != NULL) { ++ if (list->prefix == prefix) { ++ // corresponding node - return pointer to it ++ return list; ++ } else { ++ // node with different prefix - move to the next item of node list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding node was not found ++ return NULL; ++} // end find_node() ++ ++ ++/* ++ * Private static function that looks for the corresponding neighbour node in ++ * the given list of neighbours. ++ */ ++net_neighbour_list_item* Flow_network::find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list) { ++ // traverse all neighbour nodes ++ while (list != NULL) { ++ if (list->dst_node->prefix == neighbour->prefix) { ++ // corresponding neighbour node - return pointer to it ++ return list; ++ } else { ++ // neighbour node corresponding to different prefix node - move to the ++ // next item of neighbour list ++ list = list->next; ++ } ++ } ++ ++ // return NULL if corresponding neighbour node was not found ++ return NULL; ++} // end find_neighbour() ++ ++ ++/* ++ * Private static function that inserts a node representing the given IP prefix ++ * at the beginning of the given list of nodes. ++ */ ++void Flow_network::insert_node(const IP_prefix& prefix, ++ net_node_list_item** list) { ++ // allocate and initialize new prefix node ++ net_node_list_item* node = new net_node_list_item; ++ node->prefix = prefix; ++ node->visited = false; ++ node->neighbours = NULL; ++ ++ // insert new prefix node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_node() ++ ++ ++/* ++ * Private static function that inserts a neighbour node representing an edge ++ * between the given source and destination nodes at the beginning of the ++ * specified list of neighbour nodes. ++ */ ++void Flow_network::insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list) { ++ // allocate and initialize new neighbour node ++ net_neighbour_list_item* node = new net_neighbour_list_item; ++ node->src_node = src_node; ++ node->dst_node = dst_node; ++ node->capacity = capacity; ++ node->flow = flow; ++ node->orig_edge = orig_edge; ++ node->forward_edge = forward_edge; ++ ++ // insert new neighbour node at the beginning of the list ++ node->next = *list; ++ *list = node; ++ ++ return; ++} // end insert_neighbour() ++ ++ ++/* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ */ ++void Flow_network::print_node_list(const net_node_list_item* nodes) { ++ while (nodes != NULL) { ++ // print node list items ++ cout << "+-> " << nodes->prefix.get_prefix() << "/" ++ << nodes->prefix.get_length() << endl; ++ net_neighbour_list_item* neighbours = nodes->neighbours; ++ while (neighbours != NULL) { ++ // print neighbour list items ++ cout << "| +-> "; ++ if (neighbours->forward_edge) { // forward edge ++ cout << "FORWARD: "; ++ } else { // backward edge ++ cout << "BACKWARD: "; ++ } ++ cout << neighbours->src_node->prefix.get_prefix() << "/" ++ << neighbours->src_node->prefix.get_length() ++ << " --> " ++ << neighbours->dst_node->prefix.get_prefix() << "/" ++ << neighbours->dst_node->prefix.get_length() ++ << " " ++ << "(" ++ << neighbours->flow << "/" ++ << neighbours->capacity ++ << ")" << endl; ++ // move to the next neighbour ++ neighbours = neighbours->next; ++ } ++ // move to the next node ++ nodes = nodes->next; ++ } ++} // end print_node_list() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++/* ++ * Default constructor. ++ */ ++Flow_network::Flow_network() { ++ src_nodes = NULL; ++ dst_nodes = NULL; ++ s_node = NULL; ++ t_node = NULL; ++} // end Flow_network() ++ ++ ++/* ++ * Copy constructor. ++ */ ++Flow_network::Flow_network(const Flow_network& orig) { ++ // acquire members of the original object ++ const net_node_list_item* orig_src_nodes = orig.get_src_nodes(); ++ const net_node_list_item* orig_dst_nodes = orig.get_dst_nodes(); ++ const net_node_list_item* orig_s_node = orig.get_s_node(); ++ const net_node_list_item* orig_t_node = orig.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(orig_src_nodes); ++ dst_nodes = copy_node_list(orig_dst_nodes); ++ s_node = copy_node_list(orig_s_node); ++ t_node = copy_node_list(orig_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(orig_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(orig_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(orig_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(orig_s_node, s_node, NULL, src_nodes); ++} // end Filter_graph() ++ ++ ++/* ++ * Copy assignment. ++ */ ++Flow_network& Flow_network::operator=(const Flow_network& copy) { ++ // destruct the original object ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++ ++ // acquire members of the copied object ++ const net_node_list_item* copy_src_nodes = copy.get_src_nodes(); ++ const net_node_list_item* copy_dst_nodes = copy.get_dst_nodes(); ++ const net_node_list_item* copy_s_node = copy.get_s_node(); ++ const net_node_list_item* copy_t_node = copy.get_t_node(); ++ ++ // copy member node lists one by one ++ src_nodes = copy_node_list(copy_src_nodes); ++ dst_nodes = copy_node_list(copy_dst_nodes); ++ s_node = copy_node_list(copy_s_node); ++ t_node = copy_node_list(copy_t_node); ++ ++ // set pointers to neighbour nodes ++ set_destination_nodes(copy_t_node, t_node, dst_nodes, NULL); ++ set_destination_nodes(copy_dst_nodes, dst_nodes, src_nodes, t_node); ++ set_destination_nodes(copy_src_nodes, src_nodes, s_node, dst_nodes); ++ set_destination_nodes(copy_s_node, s_node, NULL, src_nodes); ++ ++ // return the original object with new content ++ return *this; ++} // end operator=() ++ ++ ++/* ++ * Destructor. ++ */ ++Flow_network::~Flow_network() { ++ remove_node_list(s_node); ++ remove_node_list(src_nodes); ++ remove_node_list(dst_nodes); ++ remove_node_list(t_node); ++} // end ~Flow_network() ++ ++ ++/* ++ * Adds an edge to the flow network. ++ */ ++void Flow_network::add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity) { ++ // get pointer to correct source node list pointer ++ net_node_list_item** src_list_ptr; ++ switch (src_list) { ++ case 0 : ++ src_list_ptr = &s_node; ++ break; ++ case 1 : ++ src_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ src_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ src_list_ptr = &t_node; ++ break; ++ } ++ ++ // get pointer to correct destination node list pointer ++ net_node_list_item** dst_list_ptr; ++ switch (dst_list) { ++ case 0 : ++ dst_list_ptr = &s_node; ++ break; ++ case 1 : ++ dst_list_ptr = &src_nodes; ++ break; ++ case 2 : ++ dst_list_ptr = &dst_nodes; ++ break; ++ case 3 : ++ dst_list_ptr = &t_node; ++ break; ++ } ++ ++ // find source prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* src_node = find_node(src_prefix, *src_list_ptr); ++ if (src_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(src_prefix, src_list_ptr); ++ src_node = *src_list_ptr; ++ } ++ ++ // find destination prefix node in the specified node list and insert such node ++ // if it does not exist ++ net_node_list_item* dst_node = find_node(dst_prefix, *dst_list_ptr); ++ if (dst_node == NULL) { ++ // node is inserted at the beginning of the list ++ insert_node(dst_prefix, dst_list_ptr); ++ dst_node = *dst_list_ptr; ++ } ++ ++ // find neighbour node corresponding to the filter and insert such node if ++ // it does not exist ++ net_neighbour_list_item* neighbour = find_neighbour(dst_node, ++ src_node->neighbours); ++ if (neighbour == NULL) { ++ // neighbour is inserted at the beginning of the list ++ insert_neighbour(src_node, dst_node, capacity, 0, orig_edge, ++ forward_edge, &(src_node->neighbours)); ++ } ++} // end add_edge() ++ ++ ++/* ++ * Transforms the flow network into a level graph. ++ */ ++void Flow_network::to_level_graph() { ++ ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ if (s_node != NULL) { ++ s_node->visited = true; ++ q.push(s_node); ++ } ++ ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue the front element of the queue ++ net_node_list_item* node = q.front(); ++ q.pop(); ++ // iterate through the list of node's neighbours ++ net_neighbour_list_item** neighbour_ptr = &(node->neighbours); ++ while ((*neighbour_ptr) != NULL) { ++ // push a pointer to a pointer to the edge on the stack ++ s.push(neighbour_ptr); ++ // if it has not been visited yet, enqueue a pointer to the target ++ // node of this edge ++ if ((*neighbour_ptr)->dst_node->visited == false) { ++ (*neighbour_ptr)->dst_node->visited = true; ++ q.push((*neighbour_ptr)->dst_node); ++ } ++ // move to the next neighbour ++ neighbour_ptr = &((*neighbour_ptr)->next); ++ } ++ } ++ ++ // initialize a set of level graph nodes with the 't' node ++ list l; ++ l.push_front(t_node); ++ ++ // do an inverse breadth-first search ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // check if the dst_node already belongs to the level graph ++ net_node_list_item* dst_node = (*neighbour_ptr)->dst_node; ++ list::iterator i; ++ for (i = l.begin(); i != l.end(); ++i) { ++ if (*i == dst_node) { ++ break; ++ } ++ } ++ if (i != l.end()) { // dst_node belongs to the level graph ++ // add also src_node to the level graph ++ l.push_front((*neighbour_ptr)->src_node); ++ } else { // dst_node does not belong to the level graph ++ // remove the edge from the flow network ++ net_neighbour_list_item* edge = (*neighbour_ptr); ++ *neighbour_ptr = (*neighbour_ptr)->next; ++ delete edge; ++ } ++ } ++} // end to_level_graph() ++ ++ ++/* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ */ ++int Flow_network::find_blocking_flow() { ++ // check if the flow network exists at all ++ if (s_node == NULL) { ++ return 0; ++ } ++ ++ int blocking_flow = 0; ++ while (1) { // inifinite loop with return statement inside ++ // initialize auxiliary variables ++ stack s; ++ stack s_capacity; ++ net_node_list_item* node = s_node; ++ // do a depth-first search ++ while (node != t_node) { ++ while (node->neighbours == NULL) { // no output edges - traverse back ++ if (s.empty()) { // the stack is empty - no way to traverse back ++ return blocking_flow; ++ } ++ // traverse back along the edge on the top of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ node = neighbour->src_node; ++ // pop the top elements of both stacks ++ s.pop(); ++ s_capacity.pop(); ++ // remove back-traversed edge ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ // push the first edge of the current node and its remaining capacity on ++ // the respective stacks ++ s.push(&(node->neighbours)); ++ s_capacity.push(node->neighbours->capacity - node->neighbours->flow); ++ // move forward along the edge - update the current node ++ node = node->neighbours->dst_node; ++ } ++ ++ // determine the smallest capacity among edges of the found path ++ int min_capacity = s_capacity.top(); ++ s_capacity.pop(); ++ while (!s_capacity.empty()) { ++ // pop the top element of the capacity stack ++ int capacity = s_capacity.top(); ++ s_capacity.pop(); ++ if (capacity < min_capacity) { // update the smallest capacity ++ min_capacity = capacity; ++ } ++ } ++ ++ // update the flow through the found path according to min_capacity value ++ while (!s.empty()) { ++ // pop the top element of the stack ++ net_neighbour_list_item** neighbour_ptr = s.top(); ++ s.pop(); ++ // update the flow in both the flow network and filter graph ++ net_neighbour_list_item* neighbour = *neighbour_ptr; ++ neighbour->flow += min_capacity; ++ if (neighbour->forward_edge) { // forward edge ++ neighbour->orig_edge->flow += min_capacity; ++ } else { // backward edge ++ neighbour->orig_edge->flow -= min_capacity; ++ } ++ // remove the edge if its remaining capacity decreases to 0 ++ if (neighbour->capacity == neighbour->flow) { ++ *neighbour_ptr = neighbour->next; ++ delete neighbour; ++ } ++ } ++ ++ // update the value of blocking flow through the flow network ++ blocking_flow += min_capacity; ++ } ++} // end find_blocking_flow() ++ ++ ++/* ++ * Prints the flow network. ++ */ ++void Flow_network::print() { ++ cout << "S_NODE:" << endl; ++ print_node_list(s_node); ++ cout << "--------------------" << endl; ++ ++ cout << "SRC_NODES:" << endl; ++ print_node_list(src_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "DST_NODES:" << endl; ++ print_node_list(dst_nodes); ++ cout << "--------------------" << endl; ++ ++ cout << "T_NODE:" << endl; ++ print_node_list(t_node); ++ cout << "--------------------" << endl; ++} +diff --git a/flow_network.h b/flow_network.h +new file mode 100644 +index 0000000..df76c3f +--- /dev/null ++++ b/flow_network.h +@@ -0,0 +1,362 @@ ++// flow_network.h: header file for Flow_network class ++// ++// Jiri Matousek, 2017 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef FLOW_NETWORK_H ++#define FLOW_NETWORK_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++#include "filter_graph.h" ++ ++// Library includes ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++ ++// Forward declarations (including typedef) to resolve circular dependency ++typedef struct net_node_list_item net_node_list_item; ++typedef struct net_neighbour_list_item net_neighbour_list_item; ++ ++/* ++ * A structure representing an item in a list of network nodes. ++ */ ++struct net_node_list_item { ++ // IP prefix represented by this node ++ IP_prefix prefix; ++ ++ // Flag showing whether the node was already visited during a traversal ++ bool visited; ++ ++ // List of neighbours ++ net_neighbour_list_item* neighbours; ++ ++ // Next item in list of network nodes ++ net_node_list_item* next; ++}; ++ ++/* ++ * A structure representing an item in a list of neighbours of a network node. ++ */ ++struct net_neighbour_list_item { ++ // Pointer to source node within list of network nodes ++ net_node_list_item* src_node; ++ ++ // Pointer to destination node within list of network nodes ++ net_node_list_item* dst_node; ++ ++ // Residual capacity of flow network's edge between neighbouring nodes ++ int capacity; ++ ++ // Flow through flow network's edge between neighbouring nodes ++ int flow; ++ ++ // Pointer to corresponding edge in filter graph ++ // (the pointer is the same for both forward and backward edges) ++ neighbour_list_item* orig_edge; ++ ++ // Flag showing whether this node represents a forward edge ++ bool forward_edge; ++ ++ // Next item in list of neighbours ++ net_neighbour_list_item* next; ++}; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a flow network -- i.e., weighted directed graph ++ * with special source (s) and terminate (t) nodes -- over a filter graph. ++ */ ++class Flow_network { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * Lists of source and destination nodes of the flow network. ++ */ ++ net_node_list_item* src_nodes; ++ net_node_list_item* dst_nodes; ++ ++ /* ++ * Special nodes 's' and 't' of the flow network. ++ */ ++ net_node_list_item* s_node; ++ net_node_list_item* t_node; ++ ++ /* ++ * Private static function that creates a deep copy of the original list. ++ * The function creates new instances of all items from the original list ++ * (as well as their neighbours sublists) and sets the value of their ++ * components according to this original list. The only exception is a ++ * pointer to destination node, which is initialized to NULL (it points ++ * to different list, thus it cannot be initialized to correct value ++ * during copying). ++ * @param orig Pointer to the constant original node list. ++ * @return Pointer to the copy of the original node list. ++ */ ++ static net_node_list_item* copy_node_list(const net_node_list_item* orig); ++ ++ /* ++ * Private static function that correctly deallocates the whole node ++ * list. ++ * The function traverses the given list and all its sublists and ++ * starting from lists of neighbours it deallocates all the traversed ++ * list items. ++ * @ param list Pointer to node list that is to be deallocated. ++ */ ++ static void remove_node_list(net_node_list_item* list); ++ ++ /* ++ * Private static function that sets correct values of destination node ++ * pointers, which cannot be correctly initialized during copying. ++ * The function simultaneously traverses neighbours lists in the orig and ++ * copy node lists. For each destination node from the orig list it looks ++ * for a corresponding item in either prev (backward edges) or next ++ * (forward edges) node list and stores the pointer to this node to the ++ * current item in the copy list. ++ * @param orig Pointer to the constant original node list. ++ * @param copy Pointer to the copy of the original node list ++ * (destination node pointers of this list are set). ++ * @param prev Pointer to the list of destination nodes of backward ++ * edges. ++ * @param next Pointer to the list of destination nodes of forward ++ * edges. ++ */ ++ static void set_destination_nodes(const net_node_list_item* orig, ++ net_node_list_item* copy, ++ net_node_list_item* prev, ++ net_node_list_item* next); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for a node with the given prefix in ++ * the given list of nodes. ++ * @param prefix Reference to a constant IP prefix of the node that the ++ * function looks for in the list. ++ * @param list Pointer to the list of nodes that is traversed during ++ * looking for the node with the given IP prefix. ++ * @return Pointer to the found node or NULL. ++ */ ++ static net_node_list_item* find_node(const IP_prefix& prefix, ++ net_node_list_item* list); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that looks for the corresponding neighbour ++ * node in the given list of neighbours. ++ * @param neighbour Pointer to a constant prefix node whose neighbour ++ * node the function looks for in the list. ++ * @param list Pointer to the list of neighbour nodes that is ++ * traversed during looking for the node corresponding ++ * to the given prefix node. ++ * @return Pointer to the found neighbour node or NULL. ++ */ ++ static net_neighbour_list_item* find_neighbour( ++ const net_node_list_item* neighbour, ++ net_neighbour_list_item* list); ++ ++ /* ++ * Private static function that inserts a node representing the given IP ++ * prefix at the beginning of the given list of nodes. ++ * @param prefix Reference to a constant IP prefix that is going to be ++ * represented by the inserted node. ++ * @param list Pointer to pointer to the list of nodes that is going ++ * to be extended by the inserted node. ++ */ ++ static void insert_node(const IP_prefix& prefix, ++ net_node_list_item** list); ++ ++ /* ++ * Private static function that inserts a neighbour node representing an ++ * edge between the given source and destination nodes at the beginning ++ * of the specified list of neighbour nodes. ++ * @param src_node Pointer to a source node of the represented ++ * edge. ++ * @param dst_node Pointer to a destination node of the represented ++ * edge. ++ * @param capacity Residual capacity of the represented edge. ++ * @param flow Flow through the represented edge. ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the inserted neighbour ++ * represents a forward edge. ++ * @param list Pointer to pointer to the list of neighbours ++ * that is going to be extended by the inserted ++ * node. ++ */ ++ static void insert_neighbour(net_node_list_item* src_node, ++ net_node_list_item* dst_node, ++ int capacity, ++ int flow, ++ neighbour_list_item* orig_edge, ++ bool forward_edge, ++ net_neighbour_list_item** list); ++ ++ /* ++ * Private static function that prints specified node list, including all ++ * sublists. ++ * @param nodes Pointer to the constant list of nodes that is to be ++ * printed. ++ */ ++ static void print_node_list(const net_node_list_item* nodes); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * All pointers are initialized to NULL. ++ */ ++ Flow_network(); ++ ++ /* ++ * Copy constructor. ++ * All pointers used by the filter graph are initialized to a deep copy ++ * of corresponding members of the original object. ++ * @param orig Reference to the constant original object. ++ */ ++ Flow_network(const Flow_network& orig); ++ ++ /* ++ * Copy assignment. ++ * The original object is destructed and its new content is constructed ++ * in a similar way as in the copy constructor. ++ * @param copy Reference to the constant copied object. ++ * @return Reference to the original object with new content. ++ */ ++ Flow_network& operator= (const Flow_network& copy); ++ ++ /* ++ * Destructor. ++ * Correctly deallocates all lists that are referenced by object members. ++ */ ++ ~Flow_network(); ++ ++ /* ++ * Get function for the src_nodes member. ++ * @return Pointer to the constant list of source nodes. ++ */ ++ inline const net_node_list_item* get_src_nodes() const { ++ return src_nodes; ++ } // end get_src_nodes() ++ ++ /* ++ * Get function for the dst_nodes member. ++ * @return Pointer to the constant list of destination nodes. ++ */ ++ inline const net_node_list_item* get_dst_nodes() const { ++ return dst_nodes; ++ } // end get_dst_nodes() ++ ++ /* ++ * Get function for the s_node member. ++ * @return Pointer to the constant special 's' node. ++ */ ++ inline const net_node_list_item* get_s_node() const { ++ return s_node; ++ } // end get_s_node() ++ ++ /* ++ * Get function for the t_node member. ++ * @return Pointer to the constant special 't' node. ++ */ ++ inline const net_node_list_item* get_t_node() const { ++ return t_node; ++ } // end get_t_node() ++ ++ /* ++ * Adds an edge to the flow network. ++ * First of all, if they are not already present, the function inserts ++ * nodes representing src_prefix and dst_prefix into node lists src_list ++ * and dst_list, respectively. Next, if it is not already present, the ++ * function inserts a neighbour node representing the edge into the list ++ * of neighbours of the node representing the source prefix. Flow item of ++ * the neighbour node is set to 0, while other items within its structure ++ * are set according to the function's parameters. ++ * @param src_prefix Reference to the IP_prefix object that ++ * determines a source node of the added edge. ++ * @param src_list Specification of a node list that contains the ++ * source node of the added edge. Mapping of the ++ * four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param dst_prefix Reference to the IP_prefix object that ++ * determines a destination node of the added edge. ++ * @param dst_list Specification of a node list that contains the ++ * destination node of the added edge. Mapping of ++ * the four allowed values to the node lists is the ++ * following: ++ * 0 ... s_node ++ * 1 ... src_node ++ * 2 ... dst_node ++ * 3 ... t_node ++ * @param orig_edge Pointer to the corresponding edge in the filter ++ * graph. ++ * @param forward_edge Flag showing whether the added edge represents a ++ * forward edge. ++ * @param capacity Residual capacity of the added edge. ++ */ ++ void add_edge(const IP_prefix& src_prefix, int src_list, ++ const IP_prefix& dst_prefix, int dst_list, ++ neighbour_list_item* orig_edge, bool forward_edge, ++ int capacity); ++ ++ /* ++ * Transforms the flow network into a level graph. ++ * During inverse BFS of the flow network, starting from a set containing ++ * the 't' node, the function incrementally extends the set by start ++ * nodes of edges ending in one of the set nodes and removes from the ++ * flow network edges that do not meet this condition. ++ */ ++ void to_level_graph(); ++ ++ /* ++ * Finds a blocking flow in the flow network, adds its value to the ++ * current flow in the corresponding filter graph, and also returns its ++ * value. ++ * The function repeatedly performs DST to find an s-t path in the flow ++ * network and the smallest capacity on this path. Once the function ++ * reaches the 't' node, it returns along the found path and increases ++ * the flow through the particular flow network edges as well as the ++ * corresponding filter graph edges. The function also updates capacities ++ * of backward-traversed flow network edges and removes them in case ++ * their capacity decreases to 0. In case of DFS ending in a node other ++ * than the 't' node, the function traverses back to the closest node ++ * with at least two output edges and removes all back-traversed edges. ++ * After each successful DFS and flow update on the found path, the ++ * function increases the value of the total flow through the flow ++ * network, which is returned at the end. ++ * The function expects that the flow network is in the form of a level ++ * graph at the time of invocation. ++ * @return The value of the blocking flow through the flow network. ++ */ ++ int find_blocking_flow(); ++ ++ /* ++ * Prints the flow network. ++ */ ++ void print(); ++}; ++ ++#endif +diff --git a/ip-address/COPYING b/ip-address/COPYING +new file mode 100644 +index 0000000..03fc9f6 +--- /dev/null ++++ b/ip-address/COPYING +@@ -0,0 +1,4 @@ ++Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++ ++Distributed under the Boost Software License, Version 1.0. (See accompanying ++file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +diff --git a/ip-address/LICENSE_1_0.txt b/ip-address/LICENSE_1_0.txt +new file mode 100644 +index 0000000..36b7cd9 +--- /dev/null ++++ b/ip-address/LICENSE_1_0.txt +@@ -0,0 +1,23 @@ ++Boost Software License - Version 1.0 - August 17th, 2003 ++ ++Permission is hereby granted, free of charge, to any person or organization ++obtaining a copy of the software and accompanying documentation covered by ++this license (the "Software") to use, reproduce, display, distribute, ++execute, and transmit the Software, and to prepare derivative works of the ++Software, and to permit third-parties to whom the Software is furnished to ++do so, all subject to the following: ++ ++The copyright notices in the Software and this entire statement, including ++the above license grant, this restriction and the following disclaimer, ++must be included in all copies of the Software, in whole or in part, and ++all derivative works of the Software, unless such copies or derivative ++works are solely in the form of machine-executable object code generated by ++a source language processor. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. +diff --git a/ip-address/README.md b/ip-address/README.md +new file mode 100644 +index 0000000..08ff928 +--- /dev/null ++++ b/ip-address/README.md +@@ -0,0 +1,18 @@ ++IP Address Proposal ++=================== ++ ++Proposed IP addresses classes for the standard C++ library. ++ ++What's Included ++--------------- ++ ++* `./include` - Reference implementation. ++ ++Tested Platforms ++---------------- ++ ++* Mac OS 10.8 using g++ 4.7 (requires `-std=c++11`) ++* Mac OS 10.8 using clang++ from Xcode 4.6 (requires `-std=c++11` and `-stdlib=libc++`) ++* Linux (CentOS 6.2) using g++ 4.7 (requires `-std=c++11`) ++* Windows 7 32-bit using Visual Studio 2010 ++* Windows 7 x64 using Visual Studio 2010 +diff --git a/ip-address/include/network b/ip-address/include/network +new file mode 100644 +index 0000000..c97ea69 +--- /dev/null ++++ b/ip-address/include/network +@@ -0,0 +1,25 @@ ++// ++// network ++// ~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_NETWORK_HEADER_FILE ++#define STDNET_NETWORK_HEADER_FILE ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/address_cast.hpp" ++#include "std/net/literals.hpp" ++ ++#endif // STDNET_NETWORK_HEADER_FILE +diff --git a/ip-address/include/std/net/detail/config.hpp b/ip-address/include/std/net/detail/config.hpp +new file mode 100644 +index 0000000..c797490 +--- /dev/null ++++ b/ip-address/include/std/net/detail/config.hpp +@@ -0,0 +1,666 @@ ++// ++// detail/config.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_CONFIG_HPP ++#define STDNET_DETAIL_CONFIG_HPP ++ ++// Default to a header-only implementation. The user must specifically request ++// separate compilation by defining either STDNET_SEPARATE_COMPILATION or ++// STDNET_DYN_LINK (as a DLL/shared library implies separate compilation). ++#if !defined(STDNET_HEADER_ONLY) ++# if !defined(STDNET_SEPARATE_COMPILATION) ++# if !defined(STDNET_DYN_LINK) ++# define STDNET_HEADER_ONLY 1 ++# endif // !defined(STDNET_DYN_LINK) ++# endif // !defined(STDNET_SEPARATE_COMPILATION) ++#endif // !defined(STDNET_HEADER_ONLY) ++ ++#if defined(STDNET_HEADER_ONLY) ++# define STDNET_DECL inline ++#else // defined(STDNET_HEADER_ONLY) ++# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++// We need to import/export our code only if the user has specifically asked ++// for it by defining STDNET_DYN_LINK. ++# if defined(STDNET_DYN_LINK) ++// Export if this is our own source, otherwise import. ++# if defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllexport) ++# else // defined(STDNET_SOURCE) ++# define STDNET_DECL __declspec(dllimport) ++# endif // defined(STDNET_SOURCE) ++# endif // defined(STDNET_DYN_LINK) ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++#endif // defined(STDNET_HEADER_ONLY) ++ ++// If STDNET_DECL isn't defined yet define it now. ++#if !defined(STDNET_DECL) ++# define STDNET_DECL ++#endif // !defined(STDNET_DECL) ++ ++// Microsoft Visual C++ detection. ++#if !defined(STDNET_MSVC) ++# if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++# define STDNET_MSVC _MSC_VER ++# endif // defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) ++#endif // defined(STDNET_MSVC) ++ ++// Support move construction and assignment on compilers known to allow it. ++#if !defined(STDNET_HAS_MOVE) ++# if !defined(STDNET_DISABLE_MOVE) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_MOVE 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_MOVE) ++#endif // !defined(STDNET_HAS_MOVE) ++ ++// If STDNET_MOVE_CAST isn't defined, and move support is available, define ++// STDNET_MOVE_ARG and STDNET_MOVE_CAST to take advantage of rvalue ++// references and perfect forwarding. ++#if defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++# define STDNET_MOVE_ARG(type) type&& ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // defined(STDNET_HAS_MOVE) && !defined(STDNET_MOVE_CAST) ++ ++// If STDNET_MOVE_CAST still isn't defined, default to a C++03-compatible ++// implementation. Note that older g++ and MSVC versions don't like it when you ++// pass a non-member function through a const reference, so for most compilers ++// we'll play it safe and stick with the old approach of passing the handler by ++// value. ++#if !defined(STDNET_MOVE_CAST) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) const type& ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define STDNET_MOVE_ARG(type) type ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# elif defined(STDNET_MSVC) ++# if (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) const type& ++# else // (_MSC_VER >= 1400) ++# define STDNET_MOVE_ARG(type) type ++# endif // (_MSC_VER >= 1400) ++# else ++# define STDNET_MOVE_ARG(type) type ++# endif ++# define STDNET_MOVE_CAST(type) static_cast ++#endif // !defined_STDNET_MOVE_CAST ++ ++// Support variadic templates on compilers known to allow it. ++#if !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++# if !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_variadic_templates) ++# define STDNET_HAS_VARIADIC_TEMPLATES 1 ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# endif // !defined(STDNET_DISABLE_VARIADIC_TEMPLATES) ++#endif // !defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++// Support the noexcept specifier on compilers known to allow it. ++#if !defined(STDNET_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_NOEXCEPT noexcept ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_NOEXCEPT noexcept ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_NOEXCEPT) ++# define STDNET_NOEXCEPT ++# endif // !defined(STDNET_NOEXCEPT) ++#endif // !defined(STDNET_NOEXCEPT) ++ ++// Support deleted functions on compilers known to allow it. ++#if !defined(STDNET_DELETED) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_DELETED = delete ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_deleted_functions) ++# define STDNET_DELETED = delete ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_DELETED) ++# define STDNET_DELETED ++# endif // !defined(STDNET_DELETED) ++#endif // !defined(STDNET_DELETED) ++ ++// Support relaxed constexpr on compilers known to allow it. ++#if !defined(STDNET_CONSTEXPR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_constexpr) ++# define STDNET_HAS_CONSTEXPR 1 ++# define STDNET_CONSTEXPR constexpr ++# endif // __has_feature(cxx_constexpr) ++# endif // defined(__clang__) ++# if !defined(STDNET_CONSTEXPR) ++# define STDNET_CONSTEXPR ++# endif // !defined(STDNET_CONSTEXPR) ++#endif // !defined(STDNET_CONSTEXPR) ++ ++// Standard library support for system errors. ++#if !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++# if !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SYSTEM_ERROR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_SYSTEM_ERROR) ++#endif // !defined(STDNET_HAS_STD_SYSTEM_ERROR) ++ ++// Compliant C++11 compilers put noexcept specifiers on error_category members. ++#if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(__clang__) ++# if __has_feature(cxx_noexcept) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // __has_feature(cxx_noexcept) ++# endif // defined(__clang__) ++# if !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++# define STDNET_ERROR_CATEGORY_NOEXCEPT ++# endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++#endif // !defined(STDNET_ERROR_CATEGORY_NOEXCEPT) ++ ++// Standard library support for arrays. ++#if !defined(STDNET_HAS_STD_ARRAY) ++# if !defined(STDNET_DISABLE_STD_ARRAY) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_ARRAY 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_ARRAY) ++#endif // !defined(STDNET_HAS_STD_ARRAY) ++ ++// Standard library support for shared_ptr and weak_ptr. ++#if !defined(STDNET_HAS_STD_SHARED_PTR) ++# if !defined(STDNET_DISABLE_STD_SHARED_PTR) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(STDNET_MSVC) ++# if (_MSC_VER >= 1600) ++# define STDNET_HAS_STD_SHARED_PTR 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(STDNET_MSVC) ++# endif // !defined(STDNET_DISABLE_STD_SHARED_PTR) ++#endif // !defined(STDNET_HAS_STD_SHARED_PTR) ++ ++// Standard library support for atomic operations. ++#if !defined(STDNET_HAS_STD_ATOMIC) ++# if !defined(STDNET_DISABLE_STD_ATOMIC) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ATOMIC 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ATOMIC) ++#endif // !defined(STDNET_HAS_STD_ATOMIC) ++ ++// Standard library support for chrono. Some standard libraries (such as the ++// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x ++// drafts, rather than the eventually standardised name of steady_clock. ++#if !defined(STDNET_HAS_STD_CHRONO) ++# if !defined(STDNET_DISABLE_STD_CHRONO) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_CHRONO 1 ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# define STDNET_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_CHRONO) ++#endif // !defined(STDNET_HAS_STD_CHRONO) ++ ++// Standard library support for addressof. ++#if !defined(STDNET_HAS_STD_ADDRESSOF) ++# if !defined(STDNET_DISABLE_STD_ADDRESSOF) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_ADDRESSOF 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_ADDRESSOF) ++#endif // !defined(STDNET_HAS_STD_ADDRESSOF) ++ ++// Standard library support for the function class. ++#if !defined(STDNET_HAS_STD_FUNCTION) ++# if !defined(STDNET_DISABLE_STD_FUNCTION) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_FUNCTION 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_FUNCTION) ++#endif // !defined(STDNET_HAS_STD_FUNCTION) ++ ++// Standard library support for type traits. ++#if !defined(STDNET_HAS_STD_TYPE_TRAITS) ++# if !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_STD_TYPE_TRAITS 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_STD_TYPE_TRAITS) ++#endif // !defined(STDNET_HAS_STD_TYPE_TRAITS) ++ ++// Standard library support for the cstdint header. ++#if !defined(STDNET_HAS_CSTDINT) ++# if !defined(STDNET_DISABLE_CSTDINT) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define STDNET_HAS_CSTDINT 1 ++# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(STDNET_DISABLE_CSTDINT) ++#endif // !defined(STDNET_HAS_CSTDINT) ++ ++// Windows target. ++#if !defined(STDNET_WINDOWS) ++# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++# define STDNET_WINDOWS 1 ++# endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++#endif // !defined(STDNET_WINDOWS) ++ ++// Windows: target OS version. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma message( \ ++ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ ++ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ ++ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ ++ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") ++# else // defined(_MSC_VER) || defined(__BORLANDC__) ++# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. ++# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. ++# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# define _WIN32_WINNT 0x0501 ++# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) ++# if defined(_WIN32) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(_WIN32) && !defined(WIN32) ++# endif // defined(_MSC_VER) ++# if defined(__BORLANDC__) ++# if defined(__WIN32__) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(__WIN32__) && !defined(WIN32) ++# endif // defined(__BORLANDC__) ++# if defined(__CYGWIN__) ++# if !defined(__USE_W32_SOCKETS) ++# error You must add -D__USE_W32_SOCKETS to your compiler options. ++# endif // !defined(__USE_W32_SOCKETS) ++# endif // defined(__CYGWIN__) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: minimise header inclusion. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++# if !defined(WIN32_LEAN_AND_MEAN) ++# define WIN32_LEAN_AND_MEAN ++# endif // !defined(WIN32_LEAN_AND_MEAN) ++# endif // !defined(STDNET_NO_WIN32_LEAN_AND_MEAN) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: suppress definition of "min" and "max" macros. ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(STDNET_NO_NOMINMAX) ++# if !defined(NOMINMAX) ++# define NOMINMAX 1 ++# endif // !defined(NOMINMAX) ++# endif // !defined(STDNET_NO_NOMINMAX) ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: No ANSI API calls. ++#if !defined(STDNET_NO_ANSI_APIS) ++# if defined(STDNET_WINDOWS) && defined(UNDER_CE) ++# define STDNET_NO_ANSI_APIS 1 ++# endif // defined(STDNET_WINDOWS) && defined(UNDER_CE) ++#endif // !defined(STDNET_NO_ANSI_APIS) ++ ++// Windows: IO Completion Ports. ++#if !defined(STDNET_HAS_IOCP) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# if !defined(UNDER_CE) ++# if !defined(STDNET_DISABLE_IOCP) ++# define STDNET_HAS_IOCP 1 ++# endif // !defined(STDNET_DISABLE_IOCP) ++# endif // !defined(UNDER_CE) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_IOCP) ++ ++// Linux: epoll, eventfd and timerfd. ++#if defined(__linux__) ++# include ++# if !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_DISABLE_EPOLL) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# define STDNET_HAS_EPOLL 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# endif // !defined(STDNET_DISABLE_EPOLL) ++# endif // !defined(STDNET_HAS_EPOLL) ++# if !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_DISABLE_EVENTFD) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# define STDNET_HAS_EVENTFD 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# endif // !defined(STDNET_DISABLE_EVENTFD) ++# endif // !defined(STDNET_HAS_EVENTFD) ++# if !defined(STDNET_HAS_TIMERFD) ++# if defined(STDNET_HAS_EPOLL) ++# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# define STDNET_HAS_TIMERFD 1 ++# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# endif // defined(STDNET_HAS_EPOLL) ++# endif // !defined(STDNET_HAS_TIMERFD) ++#endif // defined(__linux__) ++ ++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. ++#if (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) ++# if !defined(STDNET_HAS_KQUEUE) ++# if !defined(STDNET_DISABLE_KQUEUE) ++# define STDNET_HAS_KQUEUE 1 ++# endif // !defined(STDNET_DISABLE_KQUEUE) ++# endif // !defined(STDNET_HAS_KQUEUE) ++#endif // (defined(__MACH__) && defined(__APPLE__)) ++ // || defined(__FreeBSD__) ++ // || defined(__NetBSD__) ++ // || defined(__OpenBSD__) ++ ++// Solaris: /dev/poll. ++#if defined(__sun) ++# if !defined(STDNET_HAS_DEV_POLL) ++# if !defined(STDNET_DISABLE_DEV_POLL) ++# define STDNET_HAS_DEV_POLL 1 ++# endif // !defined(STDNET_DISABLE_DEV_POLL) ++# endif // !defined(STDNET_HAS_DEV_POLL) ++#endif // defined(__sun) ++ ++// Serial ports. ++#if !defined(STDNET_HAS_SERIAL_PORT) ++# if defined(STDNET_HAS_IOCP) \ ++ || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(STDNET_DISABLE_SERIAL_PORT) ++# define STDNET_HAS_SERIAL_PORT 1 ++# endif // !defined(STDNET_DISABLE_SERIAL_PORT) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(STDNET_HAS_IOCP) ++ // || !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++#endif // !defined(STDNET_HAS_SERIAL_PORT) ++ ++// Windows: stream handles. ++#if !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_STREAM_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_STREAM_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_STREAM_HANDLE) ++ ++// Windows: random access handles. ++#if !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++ ++// Windows: object handles. ++#if !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++# if !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++# if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_WINDOWS_OBJECT_HANDLE 1 ++# endif // !defined(UNDER_CE) ++# endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OBJECT_HANDLE) ++#endif // !defined(STDNET_HAS_WINDOWS_OBJECT_HANDLE) ++ ++// Windows: OVERLAPPED wrapper. ++#if !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++# if !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++# if defined(STDNET_HAS_IOCP) ++# define STDNET_HAS_WINDOWS_OVERLAPPED_PTR 1 ++# endif // defined(STDNET_HAS_IOCP) ++# endif // !defined(STDNET_DISABLE_WINDOWS_OVERLAPPED_PTR) ++#endif // !defined(STDNET_HAS_WINDOWS_OVERLAPPED_PTR) ++ ++// POSIX: stream-oriented file descriptors. ++#if !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_POSIX_STREAM_DESCRIPTOR 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_POSIX_STREAM_DESCRIPTOR) ++#endif // !defined(STDNET_HAS_POSIX_STREAM_DESCRIPTOR) ++ ++// UNIX domain sockets. ++#if !defined(STDNET_HAS_LOCAL_SOCKETS) ++# if !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_LOCAL_SOCKETS 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_LOCAL_SOCKETS) ++#endif // !defined(STDNET_HAS_LOCAL_SOCKETS) ++ ++// Can use sigaction() instead of signal(). ++#if !defined(STDNET_HAS_SIGACTION) ++# if !defined(STDNET_DISABLE_SIGACTION) ++# if !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# define STDNET_HAS_SIGACTION 1 ++# endif // !defined(STDNET_WINDOWS) && !defined(__CYGWIN__) ++# endif // !defined(STDNET_DISABLE_SIGACTION) ++#endif // !defined(STDNET_HAS_SIGACTION) ++ ++// Can use signal(). ++#if !defined(STDNET_HAS_SIGNAL) ++# if !defined(STDNET_DISABLE_SIGNAL) ++# if !defined(UNDER_CE) ++# define STDNET_HAS_SIGNAL 1 ++# endif // !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SIGNAL) ++#endif // !defined(STDNET_HAS_SIGNAL) ++ ++// Whether standard iostreams are disabled. ++//#if !defined(STDNET_NO_IOSTREAM) ++//# define STDNET_NO_IOSTREAM 1 ++//#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// Whether exception handling is disabled. ++//#if !defined(STDNET_NO_EXCEPTIONS) ++//# define STDNET_NO_EXCEPTIONS 1 ++//#endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++// Whether the typeid operator is supported. ++//#if !defined(STDNET_NO_TYPEID) ++//# define STDNET_NO_TYPEID 1 ++//#endif // !defined(STDNET_NO_TYPEID) ++ ++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to ++// get access to the various platform feature macros, e.g. to be able to test ++// for threads support. ++#if !defined(STDNET_HAS_UNISTD_H) ++# if defined(unix) \ ++ || defined(__unix) \ ++ || defined(_XOPEN_SOURCE) \ ++ || defined(_POSIX_SOURCE) \ ++ || (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) \ ++ || defined(__linux__) ++# define STDNET_HAS_UNISTD_H 1 ++# endif ++#endif // !defined(STDNET_HAS_UNISTD_H) ++#if defined(STDNET_HAS_UNISTD_H) ++# include ++#endif // defined(STDNET_HAS_UNISTD_H) ++ ++// Threads. ++#if !defined(STDNET_HAS_THREADS) ++# if !defined(STDNET_DISABLE_THREADS) ++# if defined(_MSC_VER) && defined(_MT) ++# define STDNET_HAS_THREADS 1 ++# elif defined(__BORLANDC__) && defined(__MT__) ++# define STDNET_HAS_THREADS 1 ++# elif defined(_POSIX_THREADS) ++# define STDNET_HAS_THREADS 1 ++# endif // defined(_MSC_VER) && defined(_MT) ++# endif // !defined(STDNET_DISABLE_THREADS) ++#endif // !defined(STDNET_HAS_THREADS) ++ ++// POSIX threads. ++#if !defined(STDNET_HAS_PTHREADS) ++# if defined(STDNET_HAS_THREADS) ++# if defined(_POSIX_THREADS) ++# define STDNET_HAS_PTHREADS 1 ++# endif // defined(_POSIX_THREADS) ++# endif // defined(STDNET_HAS_THREADS) ++#endif // !defined(STDNET_HAS_PTHREADS) ++ ++// Helper to prevent macro expansion. ++#define STDNET_PREVENT_MACRO_SUBSTITUTION ++ ++// Helper to define in-class constants. ++#if !defined(STDNET_STATIC_CONSTANT) ++# define STDNET_STATIC_CONSTANT(type, assignment) \ ++ static const type assignment ++#endif // !defined(STDNET_STATIC_CONSTANT) ++ ++// Microsoft Visual C++'s secure C runtime library. ++#if !defined(STDNET_HAS_SECURE_RTL) ++# if !defined(STDNET_DISABLE_SECURE_RTL) ++# if defined(STDNET_MSVC) \ ++ && (STDNET_MSVC >= 1400) \ ++ && !defined(UNDER_CE) ++# define STDNET_HAS_SECURE_RTL 1 ++# endif // defined(STDNET_MSVC) ++ // && (STDNET_MSVC >= 1400) ++ // && !defined(UNDER_CE) ++# endif // !defined(STDNET_DISABLE_SECURE_RTL) ++#endif // !defined(STDNET_HAS_SECURE_RTL) ++ ++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. ++#if !defined(STDNET_HAS_HANDLER_HOOKS) ++# if !defined(STDNET_DISABLE_HANDLER_HOOKS) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 3) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // (__GNUC__ >= 3) ++# elif !defined(__BORLANDC__) ++# define STDNET_HAS_HANDLER_HOOKS 1 ++# endif // !defined(__BORLANDC__) ++# endif // !defined(STDNET_DISABLE_HANDLER_HOOKS) ++#endif // !defined(STDNET_HAS_HANDLER_HOOKS) ++ ++// Support for the __thread keyword extension. ++#if !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++# if defined(__linux__) ++# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# if !defined(__INTEL_COMPILER) && !defined(__ICL) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# define STDNET_HAS_THREAD_KEYWORD_EXTENSION 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# endif // defined(__linux__) ++#endif // !defined(STDNET_DISABLE_THREAD_KEYWORD_EXTENSION) ++ ++// Support for POSIX ssize_t typedef. ++#if !defined(STDNET_DISABLE_SSIZE_T) ++# if defined(__linux__) \ ++ || (defined(__MACH__) && defined(__APPLE__)) ++# define STDNET_HAS_SSIZE_T 1 ++# endif // defined(__linux__) ++ // || (defined(__MACH__) && defined(__APPLE__)) ++#endif // !defined(STDNET_DISABLE_SSIZE_T) ++ ++#endif // STDNET_DETAIL_CONFIG_HPP +diff --git a/ip-address/include/std/net/detail/impl/socket_ops.ipp b/ip-address/include/std/net/detail/impl/socket_ops.ipp +new file mode 100644 +index 0000000..13b32a3 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/socket_ops.ipp +@@ -0,0 +1,260 @@ ++// ++// detail/impl/socket_ops.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_IPP ++#define STDNET_DETAIL_SOCKET_OPS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++#if defined(__hpux) ++// HP-UX doesn't declare these functions extern "C", so they are declared again ++// here to avoid linker errors about undefined symbols. ++extern "C" char* if_indextoname(unsigned int, char*); ++extern "C" unsigned int if_nametoindex(const char*); ++#endif // defined(__hpux) ++ ++inline void clear_last_error() ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ WSASetLastError(0); ++#else ++ errno = 0; ++#endif ++} ++ ++template ++inline ReturnType error_wrapper(ReturnType return_value, ++ std::error_code& ec) ++{ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ec = std::error_code(WSAGetLastError(), ++ std::experimental::net::detail::syserrc::system_category()); ++#else ++ ec = std::error_code(errno, ++ std::experimental::net::detail::syserrc::system_category()); ++#endif ++ return return_value; ++} ++ ++const char* inet_ntop(int af, const void* src, char* dest, size_t length, ++ unsigned long scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return 0; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ DWORD address_length; ++ if (af == AF_INET) ++ { ++ address_length = sizeof(sockaddr_in4_type); ++ address.v4.sin_family = AF_INET; ++ address.v4.sin_port = 0; ++ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); ++ } ++ else // AF_INET6 ++ { ++ address_length = sizeof(sockaddr_in6_type); ++ address.v6.sin6_family = AF_INET6; ++ address.v6.sin6_port = 0; ++ address.v6.sin6_flowinfo = 0; ++ address.v6.sin6_scope_id = scope_id; ++ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); ++ } ++ ++ DWORD string_length = static_cast(length); ++#if defined(STDNET_NO_ANSI_APIS) ++ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); ++ int result = error_wrapper(::WSAAddressToStringW(&address.base, ++ address_length, 0, string_buffer, &string_length), ec); ++ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); ++#else ++ int result = error_wrapper(::WSAAddressToStringA( ++ &address.base, address_length, 0, dest, &string_length), ec); ++#endif ++ ++ // Windows may set error code on success. ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ // Windows may not set an error code on failure. ++ else if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ return result == socket_error_retval ? 0 : dest; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ const char* result = error_wrapper(::inet_ntop( ++ af, src, dest, static_cast(length)), ec); ++ if (result == 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result != 0 && af == AF_INET6 && scope_id != 0) ++ { ++ using namespace std; // For strcat and sprintf. ++ char if_name[IF_NAMESIZE + 1] = "%"; ++ const in6_addr_type* ipv6_address = static_cast(src); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (!is_link_local ++ || if_indextoname(static_cast(scope_id), if_name + 1) == 0) ++ sprintf(if_name + 1, "%lu", scope_id); ++ strcat(dest, if_name); ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec) ++{ ++ clear_last_error(); ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ using namespace std; // For memcpy and strcmp. ++ ++ if (af != AF_INET && af != AF_INET6) ++ { ++ ec = std::experimental::net::detail::syserrc::address_family_not_supported; ++ return -1; ++ } ++ ++ union ++ { ++ socket_addr_type base; ++ sockaddr_storage_type storage; ++ sockaddr_in4_type v4; ++ sockaddr_in6_type v6; ++ } address; ++ int address_length = sizeof(sockaddr_storage_type); ++#if defined(STDNET_NO_ANSI_APIS) ++ int num_wide_chars = strlen(src) + 1; ++ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ++ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); ++ int result = error_wrapper(::WSAStringToAddressW( ++ wide_buffer, af, 0, &address.base, &address_length), ec); ++#else ++ int result = error_wrapper(::WSAStringToAddressA( ++ const_cast(src), af, 0, &address.base, &address_length), ec); ++#endif ++ ++ if (af == AF_INET) ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); ++ ec = std::error_code(); ++ } ++ else if (strcmp(src, "255.255.255.255") == 0) ++ { ++ static_cast(dest)->s_addr = INADDR_NONE; ++ ec = std::error_code(); ++ } ++ } ++ else // AF_INET6 ++ { ++ if (result != socket_error_retval) ++ { ++ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); ++ if (scope_id) ++ *scope_id = address.v6.sin6_scope_id; ++ ec = std::error_code(); ++ } ++ } ++ ++ // Windows may not set an error code on failure. ++ if (result == socket_error_retval && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ ++ if (result != socket_error_retval) ++ ec = std::error_code(); ++ ++ return result == socket_error_retval ? -1 : 1; ++#else // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ int result = error_wrapper(::inet_pton(af, src, dest), ec); ++ if (result <= 0 && !ec) ++ ec = std::experimental::net::detail::syserrc::invalid_argument; ++ if (result > 0 && af == AF_INET6 && scope_id) ++ { ++ using namespace std; // For strchr and atoi. ++ *scope_id = 0; ++ if (const char* if_name = strchr(src, '%')) ++ { ++ in6_addr_type* ipv6_address = static_cast(dest); ++ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) ++ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); ++ if (is_link_local) ++ *scope_id = if_nametoindex(if_name + 1); ++ if (*scope_id == 0) ++ *scope_id = atoi(if_name + 1); ++ } ++ } ++ return result; ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++} ++ ++u_long_type network_to_host_long(u_long_type value) ++{ ++ return ntohl(value); ++} ++ ++u_long_type host_to_network_long(u_long_type value) ++{ ++ return htonl(value); ++} ++ ++u_short_type network_to_host_short(u_short_type value) ++{ ++ return ntohs(value); ++} ++ ++u_short_type host_to_network_short(u_short_type value) ++{ ++ return htons(value); ++} ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_IPP +diff --git a/ip-address/include/std/net/detail/impl/system_errors.ipp b/ip-address/include/std/net/detail/impl/system_errors.ipp +new file mode 100644 +index 0000000..8b01e08 +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/system_errors.ipp +@@ -0,0 +1,94 @@ ++// ++// impl/system_errors.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++#define STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/local_free_on_block_exit.hpp" ++#include "std/net/detail/system_errors.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++class system_category : public std::error_category ++{ ++public: ++ const char* name() const STDNET_ERROR_CATEGORY_NOEXCEPT ++ { ++ return "std.net.system"; ++ } ++ ++ std::string message(int value) const ++ { ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ char* msg = 0; ++ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER ++ | FORMAT_MESSAGE_FROM_SYSTEM ++ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, ++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); ++ detail::local_free_on_block_exit local_free_obj(msg); ++ if (length && msg[length - 1] == '\n') ++ msg[--length] = '\0'; ++ if (length && msg[length - 1] == '\r') ++ msg[--length] = '\0'; ++ if (length) ++ return msg; ++ else ++ return "std.net.system error"; ++#else // defined(STDNET_WINDOWS) ++#if !defined(__sun) ++ if (value == ECANCELED) ++ return "Operation aborted."; ++#endif // !defined(__sun) ++#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) ++ using namespace std; ++ return strerror(value); ++#elif defined(__MACH__) && defined(__APPLE__) \ ++ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ ++ || defined(_AIX) || defined(__hpux) || defined(__osf__) \ ++ || defined(__ANDROID__) ++ char buf[256] = ""; ++ using namespace std; ++ strerror_r(value, buf, sizeof(buf)); ++ return buf; ++#else ++ char buf[256] = ""; ++ return strerror_r(value, buf, sizeof(buf)); ++#endif ++#endif // defined(STDNET_WINDOWS) ++ } ++}; ++ ++} // namespace syserrc ++ ++const std::error_category& system_category() ++{ ++ static syserrc::system_category instance; ++ return instance; ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_SYSTEM_ERRORS_IPP +diff --git a/ip-address/include/std/net/detail/impl/throw_error.ipp b/ip-address/include/std/net/detail/impl/throw_error.ipp +new file mode 100644 +index 0000000..92baf1c +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/throw_error.ipp +@@ -0,0 +1,49 @@ ++// ++// detail/impl/throw_error.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++#define STDNET_DETAIL_IMPL_THROW_ERROR_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void do_throw_error(const std::error_code& err) ++{ ++ std::system_error e(err); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++void do_throw_error(const std::error_code& err, const char* location) ++{ ++ std::system_error e(err, location); ++ std::experimental::net::detail::throw_exception(e); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_IMPL_THROW_ERROR_IPP +diff --git a/ip-address/include/std/net/detail/impl/winsock_init.ipp b/ip-address/include/std/net/detail/impl/winsock_init.ipp +new file mode 100644 +index 0000000..7114f6a +--- /dev/null ++++ b/ip-address/include/std/net/detail/impl/winsock_init.ipp +@@ -0,0 +1,73 @@ ++// ++// detail/impl/winsock_init.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++#define STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/winsock_init.hpp" ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++void winsock_init_base::startup(data& d, ++ unsigned char major, unsigned char minor) ++{ ++ if (::InterlockedIncrement(&d.init_count_) == 1) ++ { ++ WSADATA wsa_data; ++ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); ++ ::InterlockedExchange(&d.result_, result); ++ } ++} ++ ++void winsock_init_base::cleanup(data& d) ++{ ++ if (::InterlockedDecrement(&d.init_count_) == 0) ++ { ++ ::WSACleanup(); ++ } ++} ++ ++void winsock_init_base::throw_on_error(data& d) ++{ ++ long result = ::InterlockedExchangeAdd(&d.result_, 0); ++ if (result != 0) ++ { ++ std::error_code ec(result, ++ std::experimental::net::detail::system_category()); ++ std::experimental::net::detail::throw_error(ec, "winsock"); ++ } ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_IMPL_WINSOCK_INIT_IPP +diff --git a/ip-address/include/std/net/detail/local_free_on_block_exit.hpp b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +new file mode 100644 +index 0000000..64c9137 +--- /dev/null ++++ b/ip-address/include/std/net/detail/local_free_on_block_exit.hpp +@@ -0,0 +1,63 @@ ++// ++// detail/local_free_on_block_exit.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++#define STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class local_free_on_block_exit ++{ ++public: ++ // Constructor blocks all signals for the calling thread. ++ explicit local_free_on_block_exit(void* p) ++ : p_(p) ++ { ++ } ++ ++ // Destructor restores the previous signal mask. ++ ~local_free_on_block_exit() ++ { ++ ::LocalFree(p_); ++ } ++ ++private: ++ // Disallow copying and assignemnt. ++ local_free_on_block_exit(const local_free_on_block_exit&); ++ local_free_on_block_exit& operator=(const local_free_on_block_exit&); ++ ++ void* p_; ++}; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +diff --git a/ip-address/include/std/net/detail/old_win_sdk_compat.hpp b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +new file mode 100644 +index 0000000..3a3cdac +--- /dev/null ++++ b/ip-address/include/std/net/detail/old_win_sdk_compat.hpp +@@ -0,0 +1,218 @@ ++// ++// detail/old_win_sdk_compat.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++#define STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++// Guess whether we are building against on old Platform SDK. ++#if !defined(IN6ADDR_ANY_INIT) ++#define STDNET_HAS_OLD_WIN_SDK 1 ++#endif // !defined(IN6ADDR_ANY_INIT) ++ ++#if defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Emulation of types that are missing from old Platform SDKs. ++// ++// N.B. this emulation is also used if building for a Windows 2000 target with ++// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support ++// in that case. ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++enum ++{ ++ sockaddr_storage_maxsize = 128, // Maximum size. ++ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. ++ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), ++ sockaddr_storage_pad2size = (sockaddr_storage_maxsize - ++ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) ++}; ++ ++struct sockaddr_storage_emulation ++{ ++ short ss_family; ++ char __ss_pad1[sockaddr_storage_pad1size]; ++ __int64 __ss_align; ++ char __ss_pad2[sockaddr_storage_pad2size]; ++}; ++ ++struct in6_addr_emulation ++{ ++ union ++ { ++ u_char Byte[16]; ++ u_short Word[8]; ++ } u; ++}; ++ ++#if !defined(s6_addr) ++# define _S6_un u ++# define _S6_u8 Byte ++# define s6_addr _S6_un._S6_u8 ++#endif // !defined(s6_addr) ++ ++struct sockaddr_in6_emulation ++{ ++ short sin6_family; ++ u_short sin6_port; ++ u_long sin6_flowinfo; ++ in6_addr_emulation sin6_addr; ++ u_long sin6_scope_id; ++}; ++ ++struct ipv6_mreq_emulation ++{ ++ in6_addr_emulation ipv6mr_multiaddr; ++ unsigned int ipv6mr_interface; ++}; ++ ++struct addrinfo_emulation ++{ ++ int ai_flags; ++ int ai_family; ++ int ai_socktype; ++ int ai_protocol; ++ size_t ai_addrlen; ++ char* ai_canonname; ++ sockaddr* ai_addr; ++ addrinfo_emulation* ai_next; ++}; ++ ++#if !defined(AI_PASSIVE) ++# define AI_PASSIVE 0x1 ++#endif ++ ++#if !defined(AI_CANONNAME) ++# define AI_CANONNAME 0x2 ++#endif ++ ++#if !defined(AI_NUMERICHOST) ++# define AI_NUMERICHOST 0x4 ++#endif ++ ++#if !defined(EAI_AGAIN) ++# define EAI_AGAIN WSATRY_AGAIN ++#endif ++ ++#if !defined(EAI_BADFLAGS) ++# define EAI_BADFLAGS WSAEINVAL ++#endif ++ ++#if !defined(EAI_FAIL) ++# define EAI_FAIL WSANO_RECOVERY ++#endif ++ ++#if !defined(EAI_FAMILY) ++# define EAI_FAMILY WSAEAFNOSUPPORT ++#endif ++ ++#if !defined(EAI_MEMORY) ++# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY ++#endif ++ ++#if !defined(EAI_NODATA) ++# define EAI_NODATA WSANO_DATA ++#endif ++ ++#if !defined(EAI_NONAME) ++# define EAI_NONAME WSAHOST_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SERVICE) ++# define EAI_SERVICE WSATYPE_NOT_FOUND ++#endif ++ ++#if !defined(EAI_SOCKTYPE) ++# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT ++#endif ++ ++#if !defined(NI_NOFQDN) ++# define NI_NOFQDN 0x01 ++#endif ++ ++#if !defined(NI_NUMERICHOST) ++# define NI_NUMERICHOST 0x02 ++#endif ++ ++#if !defined(NI_NAMEREQD) ++# define NI_NAMEREQD 0x04 ++#endif ++ ++#if !defined(NI_NUMERICSERV) ++# define NI_NUMERICSERV 0x08 ++#endif ++ ++#if !defined(NI_DGRAM) ++# define NI_DGRAM 0x10 ++#endif ++ ++#if !defined(IPPROTO_IPV6) ++# define IPPROTO_IPV6 41 ++#endif ++ ++#if !defined(IPV6_UNICAST_HOPS) ++# define IPV6_UNICAST_HOPS 4 ++#endif ++ ++#if !defined(IPV6_MULTICAST_IF) ++# define IPV6_MULTICAST_IF 9 ++#endif ++ ++#if !defined(IPV6_MULTICAST_HOPS) ++# define IPV6_MULTICAST_HOPS 10 ++#endif ++ ++#if !defined(IPV6_MULTICAST_LOOP) ++# define IPV6_MULTICAST_LOOP 11 ++#endif ++ ++#if !defined(IPV6_JOIN_GROUP) ++# define IPV6_JOIN_GROUP 12 ++#endif ++ ++#if !defined(IPV6_LEAVE_GROUP) ++# define IPV6_LEAVE_GROUP 13 ++#endif ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // defined(STDNET_HAS_OLD_WIN_SDK) ++ ++// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. ++#if !defined(IPV6_V6ONLY) ++# define IPV6_V6ONLY 27 ++#endif ++ ++// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. ++#if !defined(IPPROTO_ICMPV6) ++# define IPPROTO_ICMPV6 58 ++#endif ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_OLD_WIN_SDK_COMPAT_HPP +diff --git a/ip-address/include/std/net/detail/pop_options.hpp b/ip-address/include/std/net/detail/pop_options.hpp +new file mode 100644 +index 0000000..8aa375e +--- /dev/null ++++ b/ip-address/include/std/net/detail/pop_options.hpp +@@ -0,0 +1,98 @@ ++// ++// detail/pop_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (pop) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if defined(STDNET_OBJC_WORKAROUND) ++# undef Protocol ++# undef id ++# undef STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option pop ++# pragma nopushoptwarn ++# pragma nopackwarning ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (pop) ++# pragma pack (pop) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/push_options.hpp b/ip-address/include/std/net/detail/push_options.hpp +new file mode 100644 +index 0000000..ec64373 +--- /dev/null ++++ b/ip-address/include/std/net/detail/push_options.hpp +@@ -0,0 +1,127 @@ ++// ++// detail/push_options.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++// No header guard ++ ++#if defined(__COMO__) ++ ++// Comeau C++ ++ ++#elif defined(__DMC__) ++ ++// Digital Mars C++ ++ ++#elif defined(__INTEL_COMPILER) || defined(__ICL) \ ++ || defined(__ICC) || defined(__ECC) ++ ++// Intel C++ ++ ++#elif defined(__GNUC__) ++ ++// GNU C++ ++ ++# if defined(__MINGW32__) || defined(__CYGWIN__) ++# pragma pack (push, 8) ++# endif ++ ++# if defined(__OBJC__) ++# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) ++# if !defined(STDNET_DISABLE_OBJC_WORKAROUND) ++# if !defined(Protocol) && !defined(id) ++# define Protocol cpp_Protocol ++# define id cpp_id ++# define STDNET_OBJC_WORKAROUND ++# endif ++# endif ++# endif ++# endif ++ ++#elif defined(__KCC) ++ ++// Kai C++ ++ ++#elif defined(__sgi) ++ ++// SGI MIPSpro C++ ++ ++#elif defined(__DECCXX) ++ ++// Compaq Tru64 Unix cxx ++ ++#elif defined(__ghs) ++ ++// Greenhills C++ ++ ++#elif defined(__BORLANDC__) ++ ++// Borland C++ ++ ++# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- ++# pragma nopushoptwarn ++# pragma nopackwarning ++# if !defined(__MT__) ++# error Multithreaded RTL must be selected. ++# endif // !defined(__MT__) ++ ++#elif defined(__MWERKS__) ++ ++// Metrowerks CodeWarrior ++ ++#elif defined(__SUNPRO_CC) ++ ++// Sun Workshop Compiler C++ ++ ++#elif defined(__HP_aCC) ++ ++// HP aCC ++ ++#elif defined(__MRC__) || defined(__SC__) ++ ++// MPW MrCpp or SCpp ++ ++#elif defined(__IBMCPP__) ++ ++// IBM Visual Age ++ ++#elif defined(_MSC_VER) ++ ++// Microsoft Visual C++ ++// ++// Must remain the last #elif since some other vendors (Metrowerks, for example) ++// also #define _MSC_VER ++ ++# pragma warning (disable:4103) ++# pragma warning (push) ++# pragma warning (disable:4127) ++# pragma warning (disable:4180) ++# pragma warning (disable:4244) ++# pragma warning (disable:4355) ++# pragma warning (disable:4512) ++# pragma warning (disable:4675) ++# if defined(_M_IX86) && defined(_Wp64) ++// The /Wp64 option is broken. If you want to check 64 bit portability, use a ++// 64 bit compiler! ++# pragma warning (disable:4311) ++# pragma warning (disable:4312) ++# endif // defined(_M_IX86) && defined(_Wp64) ++# pragma pack (push, 8) ++// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler ++// has a tendency to incorrectly optimise away some calls to member template ++// functions, even though those functions contain code that should not be ++// optimised away! Therefore we will always disable this optimisation option ++// for the MSVC6 compiler. ++# if (_MSC_VER < 1300) ++# pragma optimize ("g", off) ++# endif ++# if !defined(_MT) ++# error Multithreaded RTL must be selected. ++# endif // !defined(_MT) ++ ++#endif +diff --git a/ip-address/include/std/net/detail/socket_ops.hpp b/ip-address/include/std/net/detail/socket_ops.hpp +new file mode 100644 +index 0000000..02cb8a4 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_ops.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/socket_ops.hpp ++// ~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_OPS_HPP ++#define STDNET_DETAIL_SOCKET_OPS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#include ++#include "std/net/detail/socket_types.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace socket_ops { ++ ++STDNET_DECL const char* inet_ntop(int af, const void* src, char* dest, ++ size_t length, unsigned long scope_id, std::error_code& ec); ++ ++STDNET_DECL int inet_pton(int af, const char* src, void* dest, ++ unsigned long* scope_id, std::error_code& ec); ++ ++STDNET_DECL u_long_type network_to_host_long(u_long_type value); ++ ++STDNET_DECL u_long_type host_to_network_long(u_long_type value); ++ ++STDNET_DECL u_short_type network_to_host_short(u_short_type value); ++ ++STDNET_DECL u_short_type host_to_network_short(u_short_type value); ++ ++} // namespace socket_ops ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/socket_ops.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SOCKET_OPS_HPP +diff --git a/ip-address/include/std/net/detail/socket_types.hpp b/ip-address/include/std/net/detail/socket_types.hpp +new file mode 100644 +index 0000000..ee35521 +--- /dev/null ++++ b/ip-address/include/std/net/detail/socket_types.hpp +@@ -0,0 +1,186 @@ ++// ++// detail/socket_types.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SOCKET_TYPES_HPP ++#define STDNET_DETAIL_SOCKET_TYPES_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# error WinSock.h has already been included ++# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) ++# if defined(__BORLANDC__) ++# include // Needed for __errno ++# if !defined(_WSPIAPI_H_) ++# define _WSPIAPI_H_ ++# define STDNET_WSPIAPI_H_DEFINED ++# endif // !defined(_WSPIAPI_H_) ++# endif // defined(__BORLANDC__) ++# include ++# include ++# include ++# if defined(STDNET_WSPIAPI_H_DEFINED) ++# undef _WSPIAPI_H_ ++# undef STDNET_WSPIAPI_H_DEFINED ++# endif // defined(STDNET_WSPIAPI_H_DEFINED) ++# if !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# if defined(UNDER_CE) ++# pragma comment(lib, "ws2.lib") ++# elif defined(_MSC_VER) || defined(__BORLANDC__) ++# pragma comment(lib, "ws2_32.lib") ++# pragma comment(lib, "mswsock.lib") ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) ++# endif // !defined(STDNET_NO_DEFAULT_LINKED_LIBS) ++# include "std/net/detail/old_win_sdk_compat.hpp" ++#else ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# if defined(__hpux) ++# include ++# endif ++# if !defined(__hpux) || defined(__SELECT) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if !defined(__SYMBIAN32__) ++# include ++# endif ++# include ++# include ++# include ++# include ++# if defined(__sun) ++# include ++# include ++# endif ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++typedef SOCKET socket_type; ++const SOCKET invalid_socket = INVALID_SOCKET; ++const int socket_error_retval = SOCKET_ERROR; ++const int max_addr_v4_str_len = 256; ++const int max_addr_v6_str_len = 256; ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++typedef ip_mreq in4_mreq_type; ++typedef sockaddr_in sockaddr_in4_type; ++# if defined(STDNET_HAS_OLD_WIN_SDK) ++typedef in6_addr_emulation in6_addr_type; ++typedef ipv6_mreq_emulation in6_mreq_type; ++typedef sockaddr_in6_emulation sockaddr_in6_type; ++typedef sockaddr_storage_emulation sockaddr_storage_type; ++typedef addrinfo_emulation addrinfo_type; ++# else ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef addrinfo addrinfo_type; ++# endif ++typedef unsigned long ioctl_arg_type; ++typedef u_long u_long_type; ++typedef u_short u_short_type; ++typedef int signed_size_type; ++const int shutdown_receive = SD_RECEIVE; ++const int shutdown_send = SD_SEND; ++const int shutdown_both = SD_BOTH; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = 0; // Not supported on Windows. ++# if defined (_WIN32_WINNT) ++const int max_iov_len = 64; ++# else ++const int max_iov_len = 16; ++# endif ++#else ++typedef int socket_type; ++const int invalid_socket = -1; ++const int socket_error_retval = -1; ++const int max_addr_v4_str_len = INET_ADDRSTRLEN; ++#if defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; ++#else // defined(INET6_ADDRSTRLEN) ++const int max_addr_v6_str_len = 256; ++#endif // defined(INET6_ADDRSTRLEN) ++typedef sockaddr socket_addr_type; ++typedef in_addr in4_addr_type; ++# if defined(__hpux) ++// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. ++struct in4_mreq_type ++{ ++ struct in_addr imr_multiaddr; ++ struct in_addr imr_interface; ++}; ++# else ++typedef ip_mreq in4_mreq_type; ++# endif ++typedef sockaddr_in sockaddr_in4_type; ++typedef in6_addr in6_addr_type; ++typedef ipv6_mreq in6_mreq_type; ++typedef sockaddr_in6 sockaddr_in6_type; ++typedef sockaddr_storage sockaddr_storage_type; ++typedef sockaddr_un sockaddr_un_type; ++typedef addrinfo addrinfo_type; ++typedef int ioctl_arg_type; ++typedef uint32_t u_long_type; ++typedef uint16_t u_short_type; ++#if defined(STDNET_HAS_SSIZE_T) ++typedef ssize_t signed_size_type; ++#else // defined(STDNET_HAS_SSIZE_T) ++typedef int signed_size_type; ++#endif // defined(STDNET_HAS_SSIZE_T) ++const int shutdown_receive = SHUT_RD; ++const int shutdown_send = SHUT_WR; ++const int shutdown_both = SHUT_RDWR; ++const int message_peek = MSG_PEEK; ++const int message_out_of_band = MSG_OOB; ++const int message_do_not_route = MSG_DONTROUTE; ++const int message_end_of_record = MSG_EOR; ++# if defined(IOV_MAX) ++const int max_iov_len = IOV_MAX; ++# else ++// POSIX platforms are not required to define IOV_MAX. ++const int max_iov_len = 16; ++# endif ++#endif ++const int custom_socket_option_level = 0xA5100000; ++const int enable_connection_aborted_option = 1; ++const int always_fail_option = 2; ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_DETAIL_SOCKET_TYPES_HPP +diff --git a/ip-address/include/std/net/detail/system_errors.hpp b/ip-address/include/std/net/detail/system_errors.hpp +new file mode 100644 +index 0000000..4aa5c44 +--- /dev/null ++++ b/ip-address/include/std/net/detail/system_errors.hpp +@@ -0,0 +1,221 @@ ++// ++// system_errors.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_SYSTEM_ERRORS_HPP ++#define STDNET_DETAIL_SYSTEM_ERRORS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# include ++#else ++# include ++#endif ++ ++#if defined(GENERATING_DOCUMENTATION) ++/// INTERNAL ONLY. ++# define STDNET_NATIVE_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_SOCKET_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_NETDB_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_GETADDRINFO_ERROR(e) implementation_defined ++/// INTERNAL ONLY. ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) implementation_defined ++#elif defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) WSA ## e ++# define STDNET_NETDB_ERROR(e) WSA ## e ++# define STDNET_GETADDRINFO_ERROR(e) WSA ## e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_win ++#else ++# define STDNET_NATIVE_ERROR(e) e ++# define STDNET_SOCKET_ERROR(e) e ++# define STDNET_NETDB_ERROR(e) e ++# define STDNET_GETADDRINFO_ERROR(e) e ++# define STDNET_WIN_OR_POSIX(e_win, e_posix) e_posix ++#endif ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++enum system_errors ++{ ++ /// Permission denied. ++ access_denied = STDNET_SOCKET_ERROR(EACCES), ++ ++ /// Address family not supported by protocol. ++ address_family_not_supported = STDNET_SOCKET_ERROR(EAFNOSUPPORT), ++ ++ /// Address already in use. ++ address_in_use = STDNET_SOCKET_ERROR(EADDRINUSE), ++ ++ /// Transport endpoint is already connected. ++ already_connected = STDNET_SOCKET_ERROR(EISCONN), ++ ++ /// Operation already in progress. ++ already_started = STDNET_SOCKET_ERROR(EALREADY), ++ ++ /// Broken pipe. ++ broken_pipe = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_BROKEN_PIPE), ++ STDNET_NATIVE_ERROR(EPIPE)), ++ ++ /// A connection has been aborted. ++ connection_aborted = STDNET_SOCKET_ERROR(ECONNABORTED), ++ ++ /// Connection refused. ++ connection_refused = STDNET_SOCKET_ERROR(ECONNREFUSED), ++ ++ /// Connection reset by peer. ++ connection_reset = STDNET_SOCKET_ERROR(ECONNRESET), ++ ++ /// Bad file descriptor. ++ bad_descriptor = STDNET_SOCKET_ERROR(EBADF), ++ ++ /// Bad address. ++ fault = STDNET_SOCKET_ERROR(EFAULT), ++ ++ /// No route to host. ++ host_unreachable = STDNET_SOCKET_ERROR(EHOSTUNREACH), ++ ++ /// Operation now in progress. ++ in_progress = STDNET_SOCKET_ERROR(EINPROGRESS), ++ ++ /// Interrupted system call. ++ interrupted = STDNET_SOCKET_ERROR(EINTR), ++ ++ /// Invalid argument. ++ invalid_argument = STDNET_SOCKET_ERROR(EINVAL), ++ ++ /// Message too long. ++ message_size = STDNET_SOCKET_ERROR(EMSGSIZE), ++ ++ /// The name was too long. ++ name_too_long = STDNET_SOCKET_ERROR(ENAMETOOLONG), ++ ++ /// Network is down. ++ network_down = STDNET_SOCKET_ERROR(ENETDOWN), ++ ++ /// Network dropped connection on reset. ++ network_reset = STDNET_SOCKET_ERROR(ENETRESET), ++ ++ /// Network is unreachable. ++ network_unreachable = STDNET_SOCKET_ERROR(ENETUNREACH), ++ ++ /// Too many open files. ++ no_descriptors = STDNET_SOCKET_ERROR(EMFILE), ++ ++ /// No buffer space available. ++ no_buffer_space = STDNET_SOCKET_ERROR(ENOBUFS), ++ ++ /// Cannot allocate memory. ++ no_memory = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OUTOFMEMORY), ++ STDNET_NATIVE_ERROR(ENOMEM)), ++ ++ /// Operation not permitted. ++ no_permission = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_ACCESS_DENIED), ++ STDNET_NATIVE_ERROR(EPERM)), ++ ++ /// Protocol not available. ++ no_protocol_option = STDNET_SOCKET_ERROR(ENOPROTOOPT), ++ ++ /// Transport endpoint is not connected. ++ not_connected = STDNET_SOCKET_ERROR(ENOTCONN), ++ ++ /// Socket operation on non-socket. ++ not_socket = STDNET_SOCKET_ERROR(ENOTSOCK), ++ ++ /// Operation cancelled. ++ operation_aborted = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_OPERATION_ABORTED), ++ STDNET_NATIVE_ERROR(ECANCELED)), ++ ++ /// Operation not supported. ++ operation_not_supported = STDNET_SOCKET_ERROR(EOPNOTSUPP), ++ ++ /// Cannot send after transport endpoint shutdown. ++ shut_down = STDNET_SOCKET_ERROR(ESHUTDOWN), ++ ++ /// Connection timed out. ++ timed_out = STDNET_SOCKET_ERROR(ETIMEDOUT), ++ ++ /// Resource temporarily unavailable. ++ try_again = STDNET_WIN_OR_POSIX( ++ STDNET_NATIVE_ERROR(ERROR_RETRY), ++ STDNET_NATIVE_ERROR(EAGAIN)), ++ ++ /// The socket is marked non-blocking and the requested operation would block. ++ would_block = STDNET_SOCKET_ERROR(EWOULDBLOCK) ++}; ++ ++} // namespace syserrc ++ ++/// Returns the error category used for the system errors. ++extern STDNET_DECL const std::error_category& system_category(); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++namespace std { ++ ++template<> struct is_error_code_enum< ++ std::experimental::net::detail::syserrc::system_errors> ++{ ++ static const bool value = true; ++}; ++ ++} // namespace std ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++namespace syserrc { ++ ++inline std::error_code make_error_code(system_errors e) ++{ ++ return std::error_code(static_cast(e), ++ std::experimental::net::detail::system_category()); ++} ++ ++} // namespace syserrc ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#undef STDNET_NATIVE_ERROR ++#undef STDNET_SOCKET_ERROR ++#undef STDNET_NETDB_ERROR ++#undef STDNET_GETADDRINFO_ERROR ++#undef STDNET_WIN_OR_POSIX ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/system_errors.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_SYSTEM_ERRORS_HPP +diff --git a/ip-address/include/std/net/detail/throw_error.hpp b/ip-address/include/std/net/detail/throw_error.hpp +new file mode 100644 +index 0000000..4067cb7 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_error.hpp +@@ -0,0 +1,57 @@ ++// ++// detail/throw_error.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_ERROR_HPP ++#define STDNET_DETAIL_THROW_ERROR_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++STDNET_DECL void do_throw_error(const std::error_code& err); ++ ++STDNET_DECL void do_throw_error(const std::error_code& err, ++ const char* location); ++ ++inline void throw_error(const std::error_code& err) ++{ ++ if (err) ++ do_throw_error(err); ++} ++ ++inline void throw_error(const std::error_code& err, ++ const char* location) ++{ ++ if (err) ++ do_throw_error(err, location); ++} ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/throw_error.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_DETAIL_THROW_ERROR_HPP +diff --git a/ip-address/include/std/net/detail/throw_exception.hpp b/ip-address/include/std/net/detail/throw_exception.hpp +new file mode 100644 +index 0000000..0903df1 +--- /dev/null ++++ b/ip-address/include/std/net/detail/throw_exception.hpp +@@ -0,0 +1,45 @@ ++// ++// detail/throw_exception.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_THROW_EXCEPTION_HPP ++#define STDNET_DETAIL_THROW_EXCEPTION_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++// Declare the throw_exception function for all targets. ++template ++void throw_exception(const Exception& e); ++ ++// Only define the throw_exception function when exceptions are enabled. ++// Otherwise, it is up to the application to provide a definition of this ++// function. ++# if !defined(STDNET_NO_EXCEPTIONS) ++template ++void throw_exception(const Exception& e) ++{ ++ throw e; ++} ++# endif // !defined(STDNET_NO_EXCEPTIONS) ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#endif // STDNET_DETAIL_THROW_EXCEPTION_HPP +diff --git a/ip-address/include/std/net/detail/winsock_init.hpp b/ip-address/include/std/net/detail/winsock_init.hpp +new file mode 100644 +index 0000000..fc008de +--- /dev/null ++++ b/ip-address/include/std/net/detail/winsock_init.hpp +@@ -0,0 +1,94 @@ ++// ++// detail/winsock_init.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_DETAIL_WINSOCK_INIT_HPP ++#define STDNET_DETAIL_WINSOCK_INIT_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++ ++#if defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace detail { ++ ++class winsock_init_base ++{ ++protected: ++ // Structure to track result of initialisation and number of uses. POD is used ++ // to ensure that the values are zero-initialised prior to any code being run. ++ struct data ++ { ++ long init_count_; ++ long result_; ++ }; ++ ++ STDNET_DECL static void startup(data& d, ++ unsigned char major, unsigned char minor); ++ ++ STDNET_DECL static void cleanup(data& d); ++ ++ STDNET_DECL static void throw_on_error(data& d); ++}; ++ ++template ++class winsock_init : private winsock_init_base ++{ ++public: ++ winsock_init(bool allow_throw = true) ++ { ++ startup(data_, Major, Minor); ++ if (allow_throw) ++ throw_on_error(data_); ++ } ++ ++ winsock_init(const winsock_init&) ++ { ++ startup(data_, Major, Minor); ++ throw_on_error(data_); ++ } ++ ++ ~winsock_init() ++ { ++ cleanup(data_); ++ } ++ ++private: ++ static data data_; ++}; ++ ++template ++winsock_init_base::data winsock_init::data_; ++ ++// Static variable to ensure that winsock is initialised before main, and ++// therefore before any other threads can get started. ++static const winsock_init<>& winsock_init_instance = winsock_init<>(false); ++ ++} // namespace detail ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/detail/impl/winsock_init.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // defined(STDNET_WINDOWS) || defined(__CYGWIN__) ++ ++#endif // STDNET_DETAIL_WINSOCK_INIT_HPP +diff --git a/ip-address/include/std/net/ip/address.hpp b/ip-address/include/std/net/ip/address.hpp +new file mode 100644 +index 0000000..8a5e75a +--- /dev/null ++++ b/ip-address/include/std/net/ip/address.hpp +@@ -0,0 +1,328 @@ ++// ++// ip/address.hpp ++// ~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_HPP ++#define STDNET_IP_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++namespace detail { ++ ++template ++struct is_convertible_to_address_1 : false_type {}; ++ ++template ++struct is_convertible_to_address_1(declval()))>::value>::type> : true_type {}; ++ ++template ++struct is_convertible_to_address : is_convertible_to_address_1 {}; ++ ++template <> ++struct is_convertible_to_address
: false_type {}; ++ ++} // namespace detail ++ ++//template <> struct is_convertible_to_address
: false_type {}; ++ ++/// Implements version-independent IP addresses. ++/** ++ * The ip::address class provides the ability to use either IP version 4 or ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address ++{ ++public: ++ /// Default constructor. ++ STDNET_CONSTEXPR address() STDNET_NOEXCEPT ++ : type_(invalid), ++ ipv4_address_(), ++ ipv6_address_() ++ { ++ } ++ ++ /// Construct from another address type. ++ template ::value>::type> ++ STDNET_CONSTEXPR address(const T& t) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address(T&&... t); ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit address(T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ explicit address(const T1& t1, typename enable_if()))>::value>::type* = 0) ++ { *this = make_address(t1); } ++ template ++ address(T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++ template ++ address(const T1& t1, const T2& t2, typename enable_if(), declval()))>::value>::type* = 0) ++ { *this = make_address(t1, t2); } ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address(const address& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address(address&& other) STDNET_NOEXCEPT ++ : type_(other.type_), ++ ipv4_address_(other.ipv4_address_), ++ ipv6_address_(other.ipv6_address_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address& operator=(const address& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address& operator=(address&& other) STDNET_NOEXCEPT ++ { ++ type_ = other.type_; ++ ipv4_address_ = other.ipv4_address_; ++ ipv6_address_ = other.ipv6_address_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get whether the address is an IP version 4 address. ++ STDNET_CONSTEXPR bool is_v4() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv4; ++ } ++ ++ /// Get whether the address is an IP version 6 address. ++ STDNET_CONSTEXPR bool is_v6() const STDNET_NOEXCEPT ++ { ++ return type_ == ipv6; ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_loopback() : ++ (type_ == ipv6) ? ipv6_address_.is_loopback() : false; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_unspecified() : ++ (type_ == ipv6) ? ipv6_address_.is_unspecified() : false; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (type_ == ipv4) ? ipv4_address_.is_multicast() : ++ (type_ == ipv6) ? ipv6_address_.is_multicast() : false; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ != a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv4_address_ == a2.ipv4_address_; ++ return true; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address& a1, ++ const address& a2) STDNET_NOEXCEPT ++ { ++ if (a1.type_ < a2.type_) ++ return true; ++ if (a1.type_ > a2.type_) ++ return false; ++ if (a1.type_ == address::ipv4) ++ return a1.ipv4_address_ < a2.ipv4_address_; ++ if (a1.type_ == address::ipv6) ++ return a1.ipv6_address_ < a2.ipv6_address_; ++ return false; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address& a1, const address& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++private: ++ friend class address_v4; ++ friend class address_v6; ++ ++ // The type of the address. ++ enum address_type { invalid, ipv4, ipv6 } type_; ++ ++ // The underlying IPv4 address. ++ address_v4 ipv4_address_; ++ ++ // The underlying IPv6 address. ++ address_v6 ipv6_address_; ++ ++ // Helper constructor for address_cast. ++ STDNET_CONSTEXPR address(address_type type, ++ const address_v4& v4, const address_v6& v6) ++ : type_(type), ++ ipv4_address_(v4), ++ ipv6_address_(v6) ++ { ++ } ++ ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type*); ++ template friend STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++ template friend STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT; ++}; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str); ++ ++/// Create an address from an IPv4 address string in dotted decimal form, ++/// or from an IPv6 address in hexadecimal notation. ++STDNET_DECL address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#include "std/net/ip/address_cast.hpp" ++ ++#endif // STDNET_IP_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/address_cast.hpp b/ip-address/include/std/net/ip/address_cast.hpp +new file mode 100644 +index 0000000..dae3d02 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_cast.hpp +@@ -0,0 +1,106 @@ ++// ++// ip/address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_CAST_HPP ++#define STDNET_IP_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Cast a version-independent address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast a version-independent address to an IPv4 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv4 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv4) ++ ? throw bad_address_cast() ++ : addr.ipv4_address_; ++} ++ ++/// Cast a version-independent address to an IPv6 address. ++/** ++ * @throws bad_address_cast if @c a does not represent an IPv6 address. ++ */ ++template ++inline STDNET_CONSTEXPR T address_cast(const address& addr, ++ typename enable_if::value>::type*) ++{ ++ return (addr.type_ != address::ipv6) ++ ? throw bad_address_cast() ++ : addr.ipv6_address_; ++} ++ ++/// Cast an IPv4 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv4, addr, address_v6()); ++} ++ ++/// Cast an IPv4 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v4& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++/// Cast an IPv6 address to a version-independent address. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return address(address::ipv6, address_v4(), addr); ++} ++ ++/// Cast an IPv6 address to itself. ++template ++inline STDNET_CONSTEXPR T address_cast(const address_v6& addr, ++ typename enable_if::value>::type*) STDNET_NOEXCEPT ++{ ++ return addr; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/address_v4.hpp b/ip-address/include/std/net/ip/address_v4.hpp +new file mode 100644 +index 0000000..a7b9234 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v4.hpp +@@ -0,0 +1,376 @@ ++// ++// ip/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V4_HPP ++#define STDNET_IP_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++ ++/// Implements IP version 4 style addresses. ++/** ++ * The ip::address_v4 class provides the ability to use and manipulate IP ++ * version 4 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v4 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type(unsigned char a = 0, ++ unsigned char b = 0, unsigned char c = 0, unsigned char d = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v4() STDNET_NOEXCEPT ++ : bytes_(0, 0, 0, 0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v4(const bytes_type& bytes) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF) ++ ? throw std::out_of_range("address_v4 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v4(T&&... t) ++ : address_v4(make_address_v4(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v4(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v4(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v4(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v4(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v4(const address_v4& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v4(address_v4&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v4& operator=(const address_v4& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v4& operator=(address_v4&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as an unsigned long in host byte order ++ STDNET_CONSTEXPR unsigned long to_ulong() const STDNET_NOEXCEPT ++ { ++ return (static_cast(bytes_[0]) << 24) ++ | (static_cast(bytes_[1]) << 16) ++ | (static_cast(bytes_[2]) << 8) ++ | static_cast(bytes_[3]); ++ } ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string in dotted decimal format. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xFF000000) == 0x7F000000; ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return to_ulong() == 0; ++ } ++ ++ /// Determine whether the address is a class A address. ++ STDNET_CONSTEXPR bool is_class_a() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0x80000000) == 0; ++ } ++ ++ /// Determine whether the address is a class B address. ++ STDNET_CONSTEXPR bool is_class_b() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xC0000000) == 0x80000000; ++ } ++ ++ /// Determine whether the address is a class C address. ++ STDNET_CONSTEXPR bool is_class_c() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xE0000000) == 0xC0000000; ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (to_ulong() & 0xF0000000) == 0xE0000000; ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() < a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() > a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() <= a2.to_ulong(); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v4& a1, ++ const address_v4& a2) STDNET_NOEXCEPT ++ { ++ return a1.to_ulong() >= a2.to_ulong(); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v4 any() STDNET_NOEXCEPT ++ { ++ return address_v4(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v4 loopback() STDNET_NOEXCEPT ++ { ++ return address_v4(0x7F000001); ++ } ++ ++ /// Obtain an address object that represents the broadcast address. ++ static STDNET_CONSTEXPR address_v4 broadcast() STDNET_NOEXCEPT ++ { ++ return address_v4(0xFFFFFFFF); ++ } ++ ++ /// Obtain an address object that represents the broadcast address that ++ /// corresponds to the specified address and netmask. ++ static STDNET_CONSTEXPR address_v4 broadcast(const address_v4& addr, ++ const address_v4& mask) STDNET_NOEXCEPT ++ { ++ return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); ++ } ++ ++private: ++ // The underlying IPv4 address. ++ bytes_type bytes_; ++}; ++ ++/// Construct an address_v4 from raw bytes. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::bytes_type& bytes) ++{ ++ return bytes; ++} ++ ++/// Construct an address_v4 from a unsigned long in host byte order. ++inline STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long addr) ++{ ++ return ++#if ULONG_MAX > 0xFFFFFFFF ++ (addr > 0xFFFFFFFF) ++ ? throw std::out_of_range("address_v4 from unsigned long") : ++#endif // ULONG_MAX > 0xFFFFFFFF ++ address_v4::bytes_type((addr >> 24) & 0xFF, ++ (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF); ++} ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str); ++ ++/// Create an address_v4 from an IPv4 address string in dotted decimal form. ++STDNET_DECL address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++ ++/// The IPv4 unspecified address. ++STDNET_CONSTEXPR address_v4 any_v4(0); ++ ++/// The IPv4 loopback address. ++STDNET_CONSTEXPR address_v4 loopback_v4(0x7F000001); ++ ++/// The IPv4 broadcast address. ++STDNET_CONSTEXPR address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#else // defined(STDNET_HAS_CONSTEXPR) ++ ++static const address_v4 any_v4(0); ++static const address_v4 loopback_v4(0x7F000001); ++static const address_v4 broadcast_v4(0xFFFFFFFF); ++ ++#endif // defined(STDNET_HAS_CONSTEXPR) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v4 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v4.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v4.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/address_v6.hpp b/ip-address/include/std/net/ip/address_v6.hpp +new file mode 100644 +index 0000000..3c4f440 +--- /dev/null ++++ b/ip-address/include/std/net/ip/address_v6.hpp +@@ -0,0 +1,440 @@ ++// ++// ip/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_ADDRESS_V6_HPP ++#define STDNET_IP_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include "std/net/ip/fwd.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/bad_address_cast.hpp" ++#include "std/net/detail/winsock_init.hpp" ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++class address; ++class address_v4; ++ ++/// Implements IP version 6 style addresses. ++/** ++ * The ip::address_v6 class provides the ability to use and manipulate IP ++ * version 6 addresses. ++ * ++ * @par Thread Safety ++ * @e Distinct @e objects: Safe.@n ++ * @e Shared @e objects: Unsafe. ++ */ ++class address_v6 ++{ ++public: ++ /// A standard-layout type used to represent an address as an array of bytes. ++ struct bytes_type : std::array ++ { ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR bytes_type(T... t) ++ : std::array{{static_cast(t)...}} ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ explicit STDNET_CONSTEXPR bytes_type( ++ unsigned char a = 0, unsigned char b = 0, ++ unsigned char c = 0, unsigned char d = 0, ++ unsigned char e = 0, unsigned char f = 0, ++ unsigned char g = 0, unsigned char h = 0, ++ unsigned char i = 0, unsigned char j = 0, ++ unsigned char k = 0, unsigned char l = 0, ++ unsigned char m = 0, unsigned char n = 0, ++ unsigned char o = 0, unsigned char p = 0) ++# if defined(STDNET_HAS_CONSTEXPR) ++ : std::array{{a, b, c, d, e, f, g, h, i, h, k, l, m, n, o, p}} ++ { ++ } ++# else // defined(STDNET_HAS_CONSTEXPR) ++ { ++ (*this)[0] = a, (*this)[1] = b, (*this)[2] = c, (*this)[3] = d; ++ (*this)[4] = e, (*this)[5] = f, (*this)[6] = g, (*this)[7] = h; ++ (*this)[8] = i, (*this)[9] = j, (*this)[10] = k, (*this)[11] = l; ++ (*this)[12] = m, (*this)[13] = n, (*this)[14] = o, (*this)[15] = p; ++ } ++# endif // defined(STDNET_HAS_CONSTEXPR) ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ }; ++ ++ /// Default constructor. ++ STDNET_CONSTEXPR address_v6() STDNET_NOEXCEPT ++ : bytes_(0), ++ scope_id_(0) ++ { ++ } ++ ++ /// Implicit construction from bytes, in network byte order. ++ STDNET_CONSTEXPR address_v6(const bytes_type& bytes, unsigned long scope = 0) ++ : bytes_( ++#if UCHAR_MAX > 0xFF ++ (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF ++ || bytes[4] > 0xFF || bytes[5] > 0xFF || bytes[6] > 0xFF || bytes[7] > 0xFF ++ || bytes[8] > 0xFF || bytes[9] > 0xFF || bytes[10] > 0xFF || bytes[11] > 0xFF ++ || bytes[12] > 0xFF || bytes[13] > 0xFF || bytes[14] > 0xFF || bytes[15] > 0xFF) ++ ? throw std::out_of_range("address_v6 from bytes_type") : ++#endif // UCHAR_MAX > 0xFF ++ bytes), ++ scope_id_(scope) ++ { ++ } ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ /// Explicitly construct from a list of arguments. ++ template ()...))>::value>::type> ++ explicit STDNET_CONSTEXPR address_v6(T&&... t) ++ : address_v6(make_address_v6(static_cast(t)...)) ++ { ++ } ++#else // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ template ++ explicit STDNET_CONSTEXPR address_v6(T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ explicit STDNET_CONSTEXPR address_v6(const T1& t1, ++ typename enable_if()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++ template ++ STDNET_CONSTEXPR address_v6(const T1& t1, const T2& t2, ++ typename enable_if(), declval()))>::value>::type* = 0) ++ : bytes_(make_address_v6(t1, t2).to_bytes()) {} ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++ /// Copy constructor. ++ STDNET_CONSTEXPR address_v6(const address_v6& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move constructor. ++ address_v6(address_v6&& other) STDNET_NOEXCEPT ++ : bytes_(other.bytes_), scope_id_(other.scope_id_) ++ { ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// Assign from another address. ++ address_v6& operator=(const address_v6& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++ ++#if defined(STDNET_HAS_MOVE) ++ /// Move-assign from another address. ++ address_v6& operator=(address_v6&& other) STDNET_NOEXCEPT ++ { ++ bytes_ = other.bytes_; ++ scope_id_ = other.scope_id_; ++ return *this; ++ } ++#endif // defined(STDNET_HAS_MOVE) ++ ++ /// The scope ID of the address. ++ /** ++ * Returns the scope ID associated with the IPv6 address. ++ */ ++ STDNET_CONSTEXPR unsigned long scope_id() const STDNET_NOEXCEPT ++ { ++ return scope_id_; ++ } ++ ++ /// The scope ID of the address. ++ /** ++ * Modifies the scope ID associated with the IPv6 address. ++ */ ++ void scope_id(unsigned long id) STDNET_NOEXCEPT ++ { ++ scope_id_ = id; ++ } ++ ++ /// Get the address in bytes, in network byte order. ++ STDNET_CONSTEXPR bytes_type to_bytes() const STDNET_NOEXCEPT ++ { ++ return bytes_; ++ } ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string() const; ++ ++ /// Get the address as a string. ++ STDNET_DECL std::string to_string(std::error_code& ec) const; ++ ++ /// Determine whether the address is a loopback address. ++ STDNET_CONSTEXPR bool is_loopback() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 1)); ++ } ++ ++ /// Determine whether the address is unspecified. ++ STDNET_CONSTEXPR bool is_unspecified() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0) && (bytes_[11] == 0) ++ && (bytes_[12] == 0) && (bytes_[13] == 0) ++ && (bytes_[14] == 0) && (bytes_[15] == 0)); ++ } ++ ++ /// Determine whether the address is link local. ++ STDNET_CONSTEXPR bool is_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0x80)); ++ } ++ ++ /// Determine whether the address is site local. ++ STDNET_CONSTEXPR bool is_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0xc0)); ++ } ++ ++ /// Determine whether the address is a mapped IPv4 address. ++ STDNET_CONSTEXPR bool is_v4_mapped() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0) && (bytes_[1] == 0) ++ && (bytes_[2] == 0) && (bytes_[3] == 0) ++ && (bytes_[4] == 0) && (bytes_[5] == 0) ++ && (bytes_[6] == 0) && (bytes_[7] == 0) ++ && (bytes_[8] == 0) && (bytes_[9] == 0) ++ && (bytes_[10] == 0xff) && (bytes_[11] == 0xff)); ++ } ++ ++ /// Determine whether the address is a multicast address. ++ STDNET_CONSTEXPR bool is_multicast() const STDNET_NOEXCEPT ++ { ++ return (bytes_[0] == 0xff); ++ } ++ ++ /// Determine whether the address is a global multicast address. ++ STDNET_CONSTEXPR bool is_multicast_global() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x0e)); ++ } ++ ++ /// Determine whether the address is a link-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_link_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x02)); ++ } ++ ++ /// Determine whether the address is a node-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_node_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x01)); ++ } ++ ++ /// Determine whether the address is a org-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_org_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x08)); ++ } ++ ++ /// Determine whether the address is a site-local multicast address. ++ STDNET_CONSTEXPR bool is_multicast_site_local() const STDNET_NOEXCEPT ++ { ++ return ((bytes_[0] == 0xff) && ((bytes_[1] & 0x0f) == 0x05)); ++ } ++ ++ /// Compare two addresses for equality. ++ friend bool operator==(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a1.bytes_ == a2.bytes_ && a1.scope_id_ == a2.scope_id_; ++ } ++ ++ /// Compare two addresses for inequality. ++ friend bool operator!=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 == a2); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ if (a1.bytes_ < a2.bytes_) ++ return true; ++ if (a1.bytes_ > a2.bytes_) ++ return false; ++ return a1.scope_id_ < a2.scope_id_; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return a2 < a1; ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator<=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a2 < a1); ++ } ++ ++ /// Compare addresses for ordering. ++ friend bool operator>=(const address_v6& a1, ++ const address_v6& a2) STDNET_NOEXCEPT ++ { ++ return !(a1 < a2); ++ } ++ ++ /// Obtain an address object that represents any address. ++ static STDNET_CONSTEXPR address_v6 any() STDNET_NOEXCEPT ++ { ++ return address_v6(); ++ } ++ ++ /// Obtain an address object that represents the loopback address. ++ static STDNET_CONSTEXPR address_v6 loopback() STDNET_NOEXCEPT ++ { ++ return bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); ++ } ++ ++private: ++ friend STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6&); ++ ++ // The underlying IPv6 address. ++ bytes_type bytes_; ++ ++ // The scope ID associated with the address. ++ unsigned long scope_id_; ++}; ++ ++/// Construct an address_v6 from raw bytes. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ const address_v6::bytes_type& bytes, unsigned long scope_id = 0) ++{ ++ return address_v6(bytes, scope_id); ++} ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str); ++ ++/// Create an address_v6 from an IPv6 address string. ++STDNET_DECL address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT; ++ ++/// Create an IPv4-mapped address_v6 from an IPv4 address. ++inline STDNET_CONSTEXPR address_v6 make_address_v6( ++ v4_mapped_t, const address_v4& addr) STDNET_NOEXCEPT ++{ ++ return address_v6::bytes_type(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, ++ static_cast(addr.to_bytes())[0], ++ static_cast(addr.to_bytes())[1], ++ static_cast(addr.to_bytes())[2], ++ static_cast(addr.to_bytes())[3]); ++} ++ ++/// Create an address_v4 from an IPv4-mapped address_v6. ++inline STDNET_CONSTEXPR address_v4 make_address_v4( ++ v4_mapped_t, const address_v6& addr) ++{ ++ return !addr.is_v4_mapped() ? throw bad_address_cast() : ++ address_v4::bytes_type(addr.bytes_[12], addr.bytes_[13], ++ addr.bytes_[14], addr.bytes_[15]); ++} ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++/// Output an address as a string. ++/** ++ * Used to output a human-readable string for a specified address. ++ * ++ * @param os The output stream to which the string will be written. ++ * ++ * @param addr The address to be written. ++ * ++ * @return The output stream. ++ * ++ * @relates std::experimental::net::ip::address_v6 ++ */ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#include "std/net/ip/impl/address_v6.hpp" ++#if defined(STDNET_HEADER_ONLY) ++# include "std/net/ip/impl/address_v6.ipp" ++#endif // defined(STDNET_HEADER_ONLY) ++ ++#endif // STDNET_IP_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/bad_address_cast.hpp b/ip-address/include/std/net/ip/bad_address_cast.hpp +new file mode 100644 +index 0000000..bc330c2 +--- /dev/null ++++ b/ip-address/include/std/net/ip/bad_address_cast.hpp +@@ -0,0 +1,46 @@ ++// ++// ip/bad_address_cast.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_BAD_ADDRESS_CAST_HPP ++#define STDNET_IP_BAD_ADDRESS_CAST_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++/// Exception thrown on a failed address_cast. ++class bad_address_cast ++ : public bad_cast ++{ ++public: ++ virtual const char* what() const STDNET_NOEXCEPT ++ { ++ return "bad address cast"; ++ } ++}; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_BAD_ADDRESS_CAST_HPP +diff --git a/ip-address/include/std/net/ip/fwd.hpp b/ip-address/include/std/net/ip/fwd.hpp +new file mode 100644 +index 0000000..2c8f929 +--- /dev/null ++++ b/ip-address/include/std/net/ip/fwd.hpp +@@ -0,0 +1,149 @@ ++// ++// ip/fwd.hpp ++// ~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_FWD_HPP ++#define STDNET_IP_FWD_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include ++#include ++ ++#if !defined(STDNET_NO_IOSTREAM) ++# include ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++#if defined(STDNET_HAS_CONSTEXPR) ++struct v4_mapped_t { STDNET_CONSTEXPR v4_mapped_t() {} }; ++STDNET_CONSTEXPR v4_mapped_t v4_mapped; ++#else // !defined(STDNET_HAS_CONSTEXPR) ++enum v4_mapped_t { v4_mapped }; ++#endif // !defined(STDNET_HAS_CONSTEXPR) ++ ++class address; ++class address_v4; ++class address_v6; ++ ++// address comparisons: ++bool operator==(const address&, const address&) STDNET_NOEXCEPT; ++bool operator!=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator< (const address&, const address&) STDNET_NOEXCEPT; ++bool operator> (const address&, const address&) STDNET_NOEXCEPT; ++bool operator<=(const address&, const address&) STDNET_NOEXCEPT; ++bool operator>=(const address&, const address&) STDNET_NOEXCEPT; ++ ++// address creation: ++address make_address(const char*); ++address make_address(const char*, std::error_code&) STDNET_NOEXCEPT; ++address make_address(const std::string&); ++address make_address(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 comparisons: ++bool operator==(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator!=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator< (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator> (const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator<=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++bool operator>=(const address_v4&, const address_v4&) STDNET_NOEXCEPT; ++ ++// address_v4 creation: ++//STDNET_CONSTEXPR address_v4 make_address_v4(const address_v4::octets&); ++STDNET_CONSTEXPR address_v4 make_address_v4(unsigned long); ++STDNET_CONSTEXPR address_v4 make_address_v4(v4_mapped_t, const address_v6&); ++address_v4 make_address_v4(const char*); ++address_v4 make_address_v4(const char*, error_code&) STDNET_NOEXCEPT; ++address_v4 make_address_v4(const std::string&); ++address_v4 make_address_v4(const std::string&, std::error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v4 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v4&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 comparisons: ++bool operator==(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator!=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator< (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator> (const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator<=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++bool operator>=(const address_v6&, const address_v6&) STDNET_NOEXCEPT; ++ ++// address_v6 creation: ++//STDNET_CONSTEXPR address_v6 make_address_v6(const address_v6::octets&, unsigned long = 0); ++STDNET_CONSTEXPR address_v6 make_address_v6(v4_mapped_t, const address_v4&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const char*); ++address_v6 make_address_v6(const char*, error_code&) STDNET_NOEXCEPT; ++address_v6 make_address_v6(const std::string&); ++address_v6 make_address_v6(const std::string&, error_code&) STDNET_NOEXCEPT; ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++// address_v6 I/O: ++template ++ basic_ostream& operator<<( ++ basic_ostream&, const address_v6&); ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++class bad_address_cast; ++ ++// address conversion: ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address&, ++ typename enable_if::value>::type* = 0); ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template STDNET_CONSTEXPR T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v4&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++template T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_DELETED; ++template STDNET_CONSTEXPR T address_cast(const address_v6&, ++ typename enable_if::value>::type* = 0) STDNET_NOEXCEPT; ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_FWD_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.hpp b/ip-address/include/std/net/ip/impl/address.hpp +new file mode 100644 +index 0000000..82dc09c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.hpp +@@ -0,0 +1,74 @@ ++// ++// ip/impl/address.hpp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_HPP ++#define STDNET_IP_IMPL_ADDRESS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/ip/address_cast.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++inline STDNET_CONSTEXPR address::address(const T& t) STDNET_NOEXCEPT ++ : address(address_cast
(t)) ++{ ++} ++ ++#if defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++template ++inline STDNET_CONSTEXPR address::address(T&&... t) ++ : address(make_address(static_cast(t)...)) ++{ ++} ++ ++#endif // defined(STDNET_HAS_VARIADIC_TEMPLATES) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_HPP +diff --git a/ip-address/include/std/net/ip/impl/address.ipp b/ip-address/include/std/net/ip/impl/address.ipp +new file mode 100644 +index 0000000..b74189c +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address.ipp +@@ -0,0 +1,91 @@ ++// ++// ip/impl/address.ipp ++// ~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_IPP ++#define STDNET_IP_IMPL_ADDRESS_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/ip/address.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address::to_string() const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(); ++ throw bad_address_cast(); ++} ++ ++std::string address::to_string(std::error_code& ec) const ++{ ++ if (type_ == ipv4) ++ return ipv4_address_.to_string(ec); ++ if (type_ == ipv6) ++ return ipv6_address_.to_string(ec); ++ throw bad_address_cast(); ++} ++ ++address make_address(const char* str) ++{ ++ std::error_code ec; ++ address addr = make_address(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address make_address(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6 ipv6_address = make_address_v6(str, ec); ++ if (!ec) ++ return ipv6_address; ++ ++ address_v4 ipv4_address = make_address_v4(str, ec); ++ if (!ec) ++ return ipv4_address; ++ ++ return address(); ++} ++ ++address make_address(const std::string& str) ++{ ++ return make_address(str.c_str()); ++} ++ ++address make_address(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.hpp b/ip-address/include/std/net/ip/impl/address_v4.hpp +new file mode 100644 +index 0000000..8544419 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v4.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_HPP ++#define STDNET_IP_IMPL_ADDRESS_V4_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v4& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v4.ipp b/ip-address/include/std/net/ip/impl/address_v4.ipp +new file mode 100644 +index 0000000..1ed99f7 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v4.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v4.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V4_IPP ++#define STDNET_IP_IMPL_ADDRESS_V4_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include ++#include ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v4.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v4::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v4::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v4_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v4_str_len, 0, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str) ++{ ++ std::error_code ec; ++ address_v4 addr = make_address_v4(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v4 make_address_v4(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v4::bytes_type bytes; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET, str, bytes.data(), 0, ec) <= 0) ++ return address_v4(); ++ return address_v4(bytes); ++} ++ ++address_v4 make_address_v4(const std::string& str) ++{ ++ return make_address_v4(str.c_str()); ++} ++ ++address_v4 make_address_v4(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v4(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V4_IPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.hpp b/ip-address/include/std/net/ip/impl/address_v6.hpp +new file mode 100644 +index 0000000..1b3fd23 +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.hpp +@@ -0,0 +1,57 @@ ++// ++// ip/impl/address_v6.hpp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_HPP ++#define STDNET_IP_IMPL_ADDRESS_V6_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#if !defined(STDNET_NO_IOSTREAM) ++ ++#include "std/net/detail/throw_error.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++template ++std::basic_ostream& operator<<( ++ std::basic_ostream& os, const address_v6& addr) ++{ ++ std::error_code ec; ++ std::string s = addr.to_string(ec); ++ if (ec) ++ { ++ if (os.exceptions() & std::basic_ostream::failbit) ++ std::experimental::net::detail::throw_error(ec); ++ else ++ os.setstate(std::basic_ostream::failbit); ++ } ++ else ++ for (std::string::iterator i = s.begin(); i != s.end(); ++i) ++ os << os.widen(*i); ++ return os; ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // !defined(STDNET_NO_IOSTREAM) ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_HPP +diff --git a/ip-address/include/std/net/ip/impl/address_v6.ipp b/ip-address/include/std/net/ip/impl/address_v6.ipp +new file mode 100644 +index 0000000..682160b +--- /dev/null ++++ b/ip-address/include/std/net/ip/impl/address_v6.ipp +@@ -0,0 +1,90 @@ ++// ++// ip/impl/address_v6.ipp ++// ~~~~~~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_IP_IMPL_ADDRESS_V6_IPP ++#define STDNET_IP_IMPL_ADDRESS_V6_IPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/detail/config.hpp" ++#include "std/net/detail/socket_ops.hpp" ++#include "std/net/detail/system_errors.hpp" ++#include "std/net/detail/throw_error.hpp" ++#include "std/net/detail/throw_exception.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++namespace net { ++namespace ip { ++ ++std::string address_v6::to_string() const ++{ ++ std::error_code ec; ++ std::string addr = to_string(ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++std::string address_v6::to_string(std::error_code& ec) const ++{ ++ char addr_str[std::experimental::net::detail::max_addr_v6_str_len]; ++ const char* addr = ++ std::experimental::net::detail::socket_ops::inet_ntop( ++ AF_INET6, bytes_.data(), addr_str, ++ std::experimental::net::detail::max_addr_v6_str_len, ++ scope_id_, ec); ++ if (addr == 0) ++ return std::string(); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str) ++{ ++ std::error_code ec; ++ address_v6 addr = make_address_v6(str, ec); ++ std::experimental::net::detail::throw_error(ec); ++ return addr; ++} ++ ++address_v6 make_address_v6(const char* str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ address_v6::bytes_type bytes; ++ unsigned long scope_id = 0; ++ if (std::experimental::net::detail::socket_ops::inet_pton( ++ AF_INET6, str, bytes.data(), &scope_id, ec) <= 0) ++ return address_v6(); ++ return address_v6(bytes, scope_id); ++} ++ ++address_v6 make_address_v6(const std::string& str) ++{ ++ return make_address_v6(str.c_str()); ++} ++ ++address_v6 make_address_v6(const std::string& str, ++ std::error_code& ec) STDNET_NOEXCEPT ++{ ++ return make_address_v6(str.c_str(), ec); ++} ++ ++} // namespace ip ++} // namespace net ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_IP_IMPL_ADDRESS_V6_IPP +diff --git a/ip-address/include/std/net/literals.hpp b/ip-address/include/std/net/literals.hpp +new file mode 100644 +index 0000000..2f10279 +--- /dev/null ++++ b/ip-address/include/std/net/literals.hpp +@@ -0,0 +1,51 @@ ++// ++// literals.hpp ++// ~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef STDNET_LITERALS_HPP ++#define STDNET_LITERALS_HPP ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1200) ++# pragma once ++#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ++ ++#include "std/net/ip/address.hpp" ++#include "std/net/ip/address_v4.hpp" ++#include "std/net/ip/address_v6.hpp" ++ ++#include "std/net/detail/push_options.hpp" ++ ++namespace std { ++namespace experimental { ++inline namespace literals { ++inline namespace net_literals { ++ ++inline net::ip::address operator"" _ip(const char* str, std::size_t) ++{ ++ return net::ip::make_address(str); ++} ++ ++inline net::ip::address_v4 operator"" _ipv4(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v4(str); ++} ++ ++inline net::ip::address_v6 operator"" _ipv6(const char* str, std::size_t) ++{ ++ return net::ip::make_address_v6(str); ++} ++ ++} // inline namespace net_literals ++} // inline namespace literals ++} // namespace experimental ++} // namespace std ++ ++#include "std/net/detail/pop_options.hpp" ++ ++#endif // STDNET_LITERALS_HPP +diff --git a/ip_prefix.cc b/ip_prefix.cc +new file mode 100644 +index 0000000..93b59ca +--- /dev/null ++++ b/ip_prefix.cc +@@ -0,0 +1,171 @@ ++// ip_prefix.cc: IP_prefix class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++#include ++ ++ ++// Namespace aliases ++namespace ip = std::experimental::net::ip; ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++string IP_prefix::to_bitstring(unsigned short int byte) { ++ string result = "00000000"; ++ for (int i = 7; i >= 0; i--) { ++ if (byte > 0) { ++ if (byte % 2 == 0) { ++ result[i] = '0'; ++ } else { ++ result[i] = '1'; ++ } ++ byte /= 2; ++ } ++ } ++ return result; ++} // end to_bitstring() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++IP_prefix::IP_prefix(const string& str, bool bitstring) { ++ if (bitstring) { // str represents bits of an IPv4/IPv6 prefix ++ prefix = str; ++ } else { // str represents a valid IPv4/IPv6 prefix in the standard notation ++ // extract prefix ++ string pref = str.substr(0, str.find('/')); ++ // extract prefix length ++ int len = atoi(str.substr(str.find('/')+1).c_str()); ++ ++ // transform address part of the prefix into generic format ++ ip::address addr(pref); ++ ++ // transform generic format into bitstring format ++ string addr_bitstring; ++ if (addr.is_v4()) { // IPv4 ++ ip::address_v4 addr_v4(pref); ++ ip::address_v4::bytes_type addr_v4_bytes = addr_v4.to_bytes(); ++ for (ip::address_v4::bytes_type::iterator it = addr_v4_bytes.begin(); it != addr_v4_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } else if (addr.is_v6()){ // IPv6 ++ ip::address_v6 addr_v6(pref); ++ ip::address_v6::bytes_type addr_v6_bytes = addr_v6.to_bytes(); ++ for (ip::address_v6::bytes_type::iterator it = addr_v6_bytes.begin(); it != addr_v6_bytes.end(); ++it) { ++ addr_bitstring.append(to_bitstring(*it)); ++ } ++ } ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++ } ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(unsigned addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix::IP_prefix(uint128_t addr, int len) { ++ // bitstring representation of addr ++ string addr_bitstring; ++ ++ // convert addr into bitstring representation ++ addr_bitstring.append(to_bitstring(addr >> 120)); ++ addr_bitstring.append(to_bitstring(addr >> 112)); ++ addr_bitstring.append(to_bitstring(addr >> 104)); ++ addr_bitstring.append(to_bitstring(addr >> 96)); ++ addr_bitstring.append(to_bitstring(addr >> 88)); ++ addr_bitstring.append(to_bitstring(addr >> 80)); ++ addr_bitstring.append(to_bitstring(addr >> 72)); ++ addr_bitstring.append(to_bitstring(addr >> 64)); ++ addr_bitstring.append(to_bitstring(addr >> 56)); ++ addr_bitstring.append(to_bitstring(addr >> 48)); ++ addr_bitstring.append(to_bitstring(addr >> 40)); ++ addr_bitstring.append(to_bitstring(addr >> 32)); ++ addr_bitstring.append(to_bitstring(addr >> 24)); ++ addr_bitstring.append(to_bitstring(addr >> 16)); ++ addr_bitstring.append(to_bitstring(addr >> 8)); ++ addr_bitstring.append(to_bitstring(addr)); ++ ++ // store only bits actually involved in IP prefix ++ prefix = addr_bitstring.substr(0, len); ++} // end IP_prefix() ++ ++ ++IP_prefix& IP_prefix::operator= (const IP_prefix& orig) { ++ // create a copy of class members ++ prefix = orig.get_prefix(); ++ // return the created object ++ return *this; ++} // end operator= () ++ ++ ++unsigned IP_prefix::get_prefix_unsigned() const { ++ // initialize auxiliary variables ++ unsigned prefix_uns = 0; ++ unsigned pow = 1; ++ ++ // iterate over all bits of an unsigned integer from right to left ++ for (int i = 31; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns; ++} // end get_prefix_unsigned(); ++ ++ ++uint128_t IP_prefix::get_prefix_uint128_t() const { ++ // initialize auxiliary variables ++ uint128_t prefix_uns128 = 0; ++ uint128_t pow = 1; ++ ++ // iterate over all bits of a 128-bit unsigned integer from right to left ++ for (int i = 127; i >= 0; i--) { ++ if (i < (int)prefix.length()) { ++ if (prefix[i] == '1') { ++ prefix_uns128 += pow; ++ } ++ } ++ pow += pow; ++ } ++ ++ // return the prefix value ++ return prefix_uns128; ++} // end get_prefix_uint128_t(); +diff --git a/ip_prefix.h b/ip_prefix.h +new file mode 100644 +index 0000000..59efa2c +--- /dev/null ++++ b/ip_prefix.h +@@ -0,0 +1,146 @@ ++// ip_prefix.h: header file for IP_prefix class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef IP_PREFIX_H ++#define IP_PREFIX_H ++ ++ ++#include "uint128_t.h" ++#include ++ ++// Deafult namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of IPv4/IPv6 prefixes. ++ * ++ * IP prefixes are represented as bitstrings where the first character ++ * represents the MSB of an IP address. Prefix length is determined by the ++ * length of the bitstring. ++ */ ++class IP_prefix { ++ ++ ++ // ***** Private members *************************************************** ++ ++ ++ private: ++ /* ++ * String of bits representing the prefix. ++ * The first character represents the MSB of the prefix and the prefix ++ * length is given by the length of this string. ++ */ ++ string prefix; ++ ++ /* ++ * Static function for conversion of a single byte into a bitstring. ++ * @param byte Byte to be converted. ++ * @return Byte converted into bitstring. ++ */ ++ static string to_bitstring(unsigned short int byte); ++ ++ ++ // ***** Public members **************************************************** ++ ++ ++ public: ++ /* ++ * Default constructor. ++ * Constructs an empty object of the IP_prefix class ++ */ ++ inline IP_prefix() {}; ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given string ++ * representing either bits of an IPv4/IPv6 prefix (the length of the ++ * string being the lenght of the prefix) or a valid IPv4/IPv6 prefix in ++ * the standard notation. ++ * @param str String representing an IPv4/IPv6 prefix in a format ++ * determined by the bitsring parameter. ++ * @param bitstring str represents bits of an IPv4/IPv6 prefix (TRUE) ++ * or a valid IPv4/IPv6 prefix in the standard ++ * notation (FALSE). ++ */ ++ IP_prefix(const string& str, bool bitsring); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4 prefix ++ * represented by its address part (unsigned integer) and length ++ * (integer). ++ * @param addr Address part of the IPv4 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(unsigned addr, int len); ++ ++ /* ++ * Constructor. ++ * Constructs an object of the IP_prefix class from a given IPv4/IPv6 ++ * prefix represented by its address part (128-bit unsigned integer) and ++ * length (integer). ++ * @param addr Address part of the IPv4/IPv6 prefix. ++ * @param len Prefix length. ++ */ ++ IP_prefix(uint128_t addr, int len); ++ ++ /* ++ * Copy assignment. ++ * Constructs a new IP prefix object by asigning a copy of the original ++ * IP prefix object. ++ * @param orig Reference to the original IP prefix object. ++ * @return Reference to the new IP prefix object. ++ */ ++ IP_prefix& operator= (const IP_prefix& orig); ++ ++ /* ++ * Comparison operator. ++ * Compares the current IP prefix object with the given IP prefix object. ++ * @param rhs_prefix IP prefix object to be compared with the current ++ * IP prefix object. ++ * @return TRUE if IP prefixes are equal, ++ * FALSE otherwise. ++ */ ++ inline bool operator== (const IP_prefix& rhs_prefix) const { ++ return (prefix == rhs_prefix.get_prefix()); ++ } ++ ++ /* ++ * Get function for the prefix bitstring. ++ * @return Bitstring representing IPv4/IPv6 prefix. ++ */ ++ inline string get_prefix() const { ++ return prefix; ++ } // end get_prefix() ++ ++ /* ++ * Get function for the prefix in the form of an unsigned integer. ++ * @return Unsigned integer representing IPv4 prefix. ++ */ ++ unsigned get_prefix_unsigned() const; ++ ++ /* ++ * Get function for the prefix in the form of a 128-bit unsigned ++ * integer. ++ * @return 128-bit unsigned integer representing IPv4/IPv6 prefix. ++ */ ++ uint128_t get_prefix_uint128_t() const; ++ ++ /* ++ * Get function for the prefix length. ++ * @return Prefix length. ++ */ ++ inline int get_length() const { ++ return prefix.length(); ++ } // end get_prefix() ++}; ++ ++#endif +diff --git a/makefile b/makefile +old mode 100755 +new mode 100644 +index 773f4c1..3cfcce6 +--- a/makefile ++++ b/makefile +@@ -9,15 +9,16 @@ + ## See README file for details + + CC = g++ ++LIB = -I./ip-address/include + ##CFLAGS = -g -pg +-CFLAGS = -O2 ++CFLAGS = -O2 -std=c++11 $(LIB) + .cc.o: + ${CC} ${CFLAGS} -c $*.cc + + sbintree.o : stdinc.h dlist.h sbintree.h + dbintree.o : stdinc.h dlist.h dbintree.h + random_db.o : stdinc.h FilterList.h random_db.h +-custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ++custom_db.o : stdinc.h FilterList.h ProtList.h FlagList.h ExtraList.h PortList.h PrefixList.h dlist.h sbintree.h dbintree.h redundant_filter_check.h TupleBST.h custom_db.h ip_prefix.h trie.h filter_graph.h + dlist.o : stdinc.h dlist.h + redundant_filter_check.o : stdinc.h redundant_filter_check.h + ## nesting_filter_check.o : stdinc.h nesting_filter_check.h +@@ -29,8 +30,16 @@ PrefixList.o : stdinc.h PrefixList.h + FilterList.o : stdinc.h FilterList.h + TupleBST.o : stdinc.h dlist.h TupleBST.h + db_generator.o : stdinc.h random_db.h PortList.h FilterList.h custom_db.h ++uint128_t.o : uint128_t.h ++ip_prefix.o : ip_prefix.h ++trie.o : trie.h ++flow_network.o : flow_network.h ++filter_graph.o : stdinc.h filter_graph.h + +-db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o +- ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o -o db_generator ++db_generator: db_generator.o random_db.o dlist.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o sbintree.o dbintree.o redundant_filter_check.o FilterList.o TupleBST.o custom_db.o uint128_t.o ip_prefix.o trie.o flow_network.o filter_graph.o ++ ${CC} ${CFLAGS} db_generator.o random_db.o dlist.o sbintree.o dbintree.o ProtList.o FlagList.o ExtraList.o PortList.o PrefixList.o FilterList.o redundant_filter_check.o TupleBST.o custom_db.o uint128_t.o ip_prefix.o trie.o flow_network.o filter_graph.o -o db_generator + + all: db_generator ++ ++clean: ++ rm -rf *.o db_generator +diff --git a/random_db.cc b/random_db.cc +index 8da4c37..b71ff3e 100644 +--- a/random_db.cc ++++ b/random_db.cc +@@ -16,28 +16,66 @@ int random_db_gen(int num_filters, FilterList* filters){ + int i; + unsigned temp1; + unsigned temp2; ++ uint128_t temp1_128; ++ uint128_t temp2_128; ++ uint128_t temp3_128; ++ uint128_t temp4_128; + struct filter temp_filter; + + for (i = 0; i < num_filters; i++) { +- // Source Address +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.sa = temp1; ++ if (ADDRLEN == 32) { //IPv4 ++ // Source Address ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa = temp1; + +- // Source Address Length +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.sa_len = (temp1 >> 27); ++ // Source Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa_len = (temp1 >> 27); + +- // Destination Address +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.da = temp1; ++ // Destination Address ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da = temp1; + +- // Destination Address Length +- temp1 = 0; +- temp1 = mrand48(); +- temp_filter.da_len = (temp1 >> 27); ++ // Destination Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da_len = (temp1 >> 27); ++ } else { // IPv6 ++ // Source Address ++ temp1_128 = temp2_128 = temp3_128 = temp4_128 = 0; ++ temp1_128 = lrand48(); ++ temp2_128 = lrand48(); ++ temp3_128 = lrand48(); ++ temp4_128 = lrand48(); ++ temp2_128 <<= 32; ++ temp3_128 <<= 64; ++ temp4_128 <<= 96; ++ temp_filter.sa = temp4_128 | temp3_128 | temp2_128 | temp1_128; ++ ++ // Source Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.sa_len = (temp1 >> 25); ++ ++ // Destination Address ++ temp1_128 = temp2_128 = temp3_128 = temp4_128 = 0; ++ temp1_128 = lrand48(); ++ temp2_128 = lrand48(); ++ temp3_128 = lrand48(); ++ temp4_128 = lrand48(); ++ temp2_128 <<= 32; ++ temp3_128 <<= 64; ++ temp4_128 <<= 96; ++ temp_filter.da = temp4_128 | temp3_128 | temp2_128 | temp1_128; ++ ++ // Destination Address Length ++ temp1 = 0; ++ temp1 = mrand48(); ++ temp_filter.da_len = (temp1 >> 25); ++ } + + // Source Port Ranges + temp1 = 0; +diff --git a/redundant_filter_check.cc b/redundant_filter_check.cc +index 38771e7..fbac9d3 100644 +--- a/redundant_filter_check.cc ++++ b/redundant_filter_check.cc +@@ -21,7 +21,7 @@ int redundant_check(struct filter filt1, struct filter filt2){ + + int sa_prefix_match(struct filter filt1, struct filter filt2){ + +- unsigned addr1, addr2; ++ uint128_t addr1, addr2; + int len; + + len = filt1.sa_len; +@@ -33,11 +33,11 @@ int sa_prefix_match(struct filter filt1, struct filter filt2){ + // Check source address prefixes + addr1 = filt1.sa; + // mask bits +- addr1 = ((addr1 >> (32-len)) << (32-len)); ++ addr1 = ((addr1 >> (128-len)) << (128-len)); + + addr2 = filt2.sa; + // mask bits +- addr2 = ((addr2 >> (32-len)) << (32-len)); ++ addr2 = ((addr2 >> (128-len)) << (128-len)); + } + // Check source address match + if (addr1 == addr2) return 1; +@@ -47,7 +47,7 @@ int sa_prefix_match(struct filter filt1, struct filter filt2){ + + int da_prefix_match(struct filter filt1, struct filter filt2){ + +- unsigned addr1, addr2; ++ uint128_t addr1, addr2; + int len; + + len = filt1.da_len; +@@ -59,11 +59,11 @@ int da_prefix_match(struct filter filt1, struct filter filt2){ + // Check source address prefixes + addr1 = filt1.da; + // mask bits +- addr1 = ((addr1 >> (32-len)) << (32-len)); ++ addr1 = ((addr1 >> (128-len)) << (128-len)); + + addr2 = filt2.da; + // mask bits +- addr2 = ((addr2 >> (32-len)) << (32-len)); ++ addr2 = ((addr2 >> (128-len)) << (128-len)); + } + + // Check source address match +diff --git a/sbintree.cc b/sbintree.cc +index d755099..062fbaf 100644 +--- a/sbintree.cc ++++ b/sbintree.cc +@@ -13,12 +13,12 @@ + + sbintree::sbintree() { + // Initialize to graph with N vertices and no edges. +- skew = new float[33]; +- p1child = new float[33]; +- p2child = new float[33]; ++ skew = new float[129]; ++ p1child = new float[129]; ++ p2child = new float[129]; + num_stnodes = 0; + root = NULL; +- for (int u = 0; u < 33; u++) { ++ for (int u = 0; u < 129; u++) { + skew[u] = 0; + p1child[u] = 0; + p2child[u] = 0; +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -96,13 +96,13 @@ void sbintree::read_skew(FILE* fp_in){ + // printf("matches = %d\n",matches); + // printf("level = %d, skew = %.4f\n",level,skew); + if (matches == 4) { +- if (level <= 32) { ++ if (level <= 128) { + p1child[level] = p1_t; + p2child[level] = p2_t; + skew[level] = f_skew; + } + else { +- fprintf(stderr,"Level for source address skew is greater than 32.\n"); ++ fprintf(stderr,"Level for source address skew is greater than 128.\n"); + exit(1); + } + // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); +@@ -117,7 +117,7 @@ void sbintree::read_skew(FILE* fp_in){ + void sbintree::print_skew(FILE *fp) { + + fprintf(fp,"Level\tp1\tp2\tSkew\n"); +- for (int i = 0; i < 33; i++) { ++ for (int i = 0; i < 129; i++) { + fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", + i,p1child[i],p2child[i],skew[i]); + } +@@ -125,7 +125,7 @@ void sbintree::print_skew(FILE *fp) { + } + + void sbintree::build_tree(dlist* Flist, struct filter filters[]){ +- unsigned int addr = 0; ++ uint128_t addr = 0; + // Create copy of list + dlist* temp_list = new dlist; + (*temp_list)=(Flist); +@@ -138,7 +138,7 @@ void sbintree::build_tree(dlist* Flist, struct filter filters[]){ + return; + } + +-void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest){ ++void sbintree::add_node(struct stnode *prnt, int lev, int dir, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest){ + int Flist_size = 0; + /* + printf("add_node:\n"); +@@ -215,7 +215,7 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + + double temp; + int path; +- unsigned int addr0, addr1; ++ uint128_t addr0, addr1; + int lev1; + + // If list is empty, return +@@ -231,19 +231,19 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + if (lev == 0) { + addr0 = 0; + addr1 = 1; +- addr1 = addr1 << 31; ++ addr1 = addr1 << 127; + } else { +- addr0 = addr >> (32 - lev); +- addr0 = addr0 << (32 - lev); +- addr1 = addr >> (32 - lev); ++ addr0 = addr >> (128 - lev); ++ addr0 = addr0 << (128 - lev); ++ addr1 = addr >> (128 - lev); + addr1 = addr1 << 1; + addr1 += 1; +- addr1 = addr1 << (31 - lev); ++ addr1 = addr1 << (127 - lev); + } + // If at the nesting threshold and list has more than one child, + // then split list (allocate all nodes with level == lev1 to one path) + // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); +- if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 31)){ ++ if ((Flist_size > 1) && (MyNest >= Nest - 1) && (lev1_flag == 1) && (lev < 127)){ + // Allocate nest_list + dlist *nest_list = new dlist(); + dlist *other_list = new dlist(); +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew +diff --git a/sbintree.h b/sbintree.h +index b085696..8130000 100644 +--- a/sbintree.h ++++ b/sbintree.h +@@ -31,7 +31,7 @@ class sbintree { + float *p1child; // probability that a node at a given level has one child + float *p2child; // probability that a node at a given level has two children + int num_stnodes; // number of tree nodes +- void add_node(struct stnode *prnt, int lev, int dir, unsigned int addr, dlist* Flist, struct filter filters[], int CurrNest); ++ void add_node(struct stnode *prnt, int lev, int dir, uint128_t addr, dlist* Flist, struct filter filters[], int CurrNest); + int Nest; // Maximum allowed nesting + public: + sbintree(); +@@ -43,6 +43,17 @@ class sbintree { + void scale_skew(float scale_factor); // scale branching and skew according to scaling factor + void print_skew(FILE*); // print average skew per level + void build_tree(dlist* Flist, struct filter filters[]); ++ ++ // get methods for selected private members ++ inline float* get_skew() { ++ return skew; ++ }; ++ inline float* get_p1child() { ++ return p1child; ++ }; ++ inline float* get_p2child() { ++ return p2child; ++ }; + }; + + #endif +diff --git a/stdinc.h b/stdinc.h +index f566e0f..3c2f685 100644 +--- a/stdinc.h ++++ b/stdinc.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include "uint128_t.h" + + typedef char bit; + // const int false = 0; +@@ -24,7 +25,7 @@ inline double max(double x, double y) { return x > y ? x : y; } + inline int min(int x, int y) { return x < y ? x : y; } + inline double min(double x, double y) { return x < y ? x : y; } + inline int abs(int x) { return x < 0 ? -x : x; } +-inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } ++// inline bit isdigit(int c) { return (c >= '0') && (c <= '9'); } + + inline void warning(char* p) { fprintf(stderr,"Warning:%s \n",p); } + inline void fatal(char* string) {fprintf(stderr,"Fatal:%s\n",string); exit(1); } +@@ -49,15 +50,15 @@ inline int randgeo(double p) { return int(.999999 + log(randfrac())/log(1-p)); } + + // Filter database stuff + +-#define ADDRLEN 32 // IPv4 ++extern int ADDRLEN; // set in db_generator.cc + #define ADDRBYTES ADDRLEN/8 + #define MAXFILTERS 130000 + #define MAXSTR 100 + // #define NULL 0 + + struct filter { +- unsigned sa; // IP source address +- unsigned da; // IP destination address ++ uint128_t sa; // IP source address ++ uint128_t da; // IP destination address + int sa_len; // IP source address mask length + int da_len; // IP destination address mask length + int sp[2]; // Transport source port range [low,high] +@@ -69,6 +70,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; +diff --git a/trie.cc b/trie.cc +new file mode 100644 +index 0000000..12f15de +--- /dev/null ++++ b/trie.cc +@@ -0,0 +1,1190 @@ ++// trie.cc: trie class definition ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++// User includes ++#include "trie.h" ++ ++// Library includes ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Auxiliary class definitions ++// **************************************************************************** ++ ++class trie_nodes_greater_than_prefixes { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the number of prefixes ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if (node2->prefixes < node1->prefixes) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++class trie_nodes_greater_than_weight { ++public: ++ // implements operation "node1 is GREATER THAN node2" ++ // according to the total weight of nodes' subtrees ++ bool operator()(trie_node* node1, trie_node* node2) ++ { ++ if ((node2->zero_weight + node2->one_weight) < ++ (node1->zero_weight + node1->one_weight)) { ++ return true; ++ } else { ++ return false; ++ } ++ } ++}; ++ ++ ++// **************************************************************************** ++// Function definitions ++// **************************************************************************** ++ ++ ++// ***** Private functions **************************************************** ++ ++ ++trie_node* Trie::copy(const trie_node* node, int level) { ++ // create a pointer to the root of a new trie ++ trie_node* copy_root; ++ // copy the given subtree ++ if (node != NULL) { // non-empty subtree ++ copy_root = new trie_node; ++ copy_root->level = level; ++ copy_root->prefixes = node->prefixes; ++ copy_root->prefix_nesting_branches = node->prefix_nesting_branches; ++ copy_root->zero = copy(node->zero, level+1); ++ copy_root->zero_weight = node->zero_weight; ++ copy_root->one = copy(node->one, level+1); ++ copy_root->one_weight = node->one_weight; ++ } else { // empty subtree ++ copy_root = NULL; ++ } ++ // return the pointer to the root node of the copy ++ return copy_root; ++} // end copy() ++ ++ ++void Trie::destruct(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ destruct(node->zero); ++ destruct(node->one); ++ delete node; ++ } ++ return; ++} // end destruct() ++ ++ ++int Trie::compute_weights(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero_weight = compute_weights(node->zero); ++ node->one_weight = compute_weights(node->one); ++ return node->zero_weight + node->one_weight + node->prefixes; ++ } else { // empty subtree ++ return 0; ++ } ++} // end compute_weights() ++ ++ ++float Trie::compute_skew(trie_node* node) { ++ if (node->zero_weight > node->one_weight) { // lighter 1-subtree ++ return 1 - ((float)node->one_weight / (float)node->zero_weight); ++ } else { // lighter 0-subtree ++ return 1 - ((float)node->zero_weight / (float)node->one_weight); ++ } ++} // end compute_skew() ++ ++ ++int Trie::get_prefix_nesting(const trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ // get prefix nesting from successor nodes ++ int zero_nesting = get_prefix_nesting(node->zero); ++ int one_nesting = get_prefix_nesting(node->one); ++ // will this node increase prefix nesting? ++ int is_prefix; ++ if (node->prefixes > 0) { // this is a prefix node ++ is_prefix = 1; ++ } else { ++ is_prefix = 0; ++ } ++ // return maximum of successors' nesting, possibly incremented ++ if (zero_nesting > one_nesting) { ++ return zero_nesting + is_prefix; ++ } else { ++ return one_nesting + is_prefix; ++ } ++ } else { // empty subtree ++ return 0; ++ } ++} // end get_prefix_nesting() ++ ++ ++void Trie::remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches) { ++ trie_node** lightest_subtree_ptr = NULL; ++ int* lightest_weight_ptr = NULL; ++ // find the lightest subtree of nodes stored in the queue ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // auxiliary variables ++ trie_node** subtree_ptr = NULL; ++ int* weight_ptr = NULL; ++ if (one_child) { // consider only nodes with one child ++ // consider only nodes that can become a valid leaf node ++ if (node->prefixes > 0) { ++ // one-subtree only ++ if ((node->zero == NULL) && (node->one != NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ // zero-subtree only ++ } else if ((node->zero != NULL) && (node->one == NULL)) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } ++ } ++ } else { // consider only nodes with two children ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // determine lighter subtree ++ if (node->zero_weight <= node->one_weight) { ++ // the last maximum prefix nesting branch is not going through ++ // the zero-subtree ++ if (node->zero->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->zero); ++ weight_ptr = &(node->zero_weight); ++ } ++ } else { ++ // the last maximum prefix nesting branch is not going through ++ // the one-subtree ++ if (node->one->prefix_nesting_branches < ++ prefix_nesting_branches) { ++ subtree_ptr = &(node->one); ++ weight_ptr = &(node->one_weight); ++ } ++ } ++ } ++ } ++ // no lightest subtree has been found so far ++ if (lightest_weight_ptr == NULL) { ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } else { // a candidate for the lightest subtree has already been found ++ if (weight_ptr != NULL) { // new candidate for the lightest subtree ++ // new lightest subtree ++ if ((*weight_ptr) < (*lightest_weight_ptr)) { ++ lightest_subtree_ptr = subtree_ptr; ++ lightest_weight_ptr = weight_ptr; ++ } ++ } ++ } ++ } // end of while (!q.empty()) ++ // if lightest subtree, which can be removed, has been found ++ if (lightest_subtree_ptr != NULL) { ++ destruct(*lightest_subtree_ptr); ++ *lightest_subtree_ptr = NULL; ++ *lightest_weight_ptr = 0; ++ } ++ return; ++} // end remove_lightest_subtree() ++ ++ ++int Trie::mark_prefix_nesting_branches(trie_node* node, int prefix_nesting, ++ int seen_prefixes) { ++ if (node == NULL) { // empty subtree ++ return 0; ++ } ++ if (node->prefixes > 0) { // the current root node is a prefix node ++ seen_prefixes++; ++ } ++ // when a prefix nesting branch has been found ++ if (seen_prefixes == prefix_nesting) { ++ node->prefix_nesting_branches = 1; ++ } else { // look for maximum prefix nesting branches in subtrees ++ int branches_zero = mark_prefix_nesting_branches(node->zero, ++ prefix_nesting, ++ seen_prefixes); ++ int branches_one = mark_prefix_nesting_branches(node->one, ++ prefix_nesting, ++ seen_prefixes); ++ node->prefix_nesting_branches = branches_zero + branches_one; ++ } ++ return node->prefix_nesting_branches; ++} // end mark_refix_nesting_branches() ++ ++ ++int Trie::get_removable_prefixes(trie_node* node) { ++ if (node == NULL) { ++ return 0; ++ } ++ int removable_prefixes_zero = get_removable_prefixes(node->zero); ++ int removable_prefixes_one = get_removable_prefixes(node->one); ++ int removable_prefixes_this = node->prefixes; ++ // keep at least one prefix in a leaf node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_this--; ++ } ++ // different handling for 2-children node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // allow removing prefixes from subtrees only if both subtrees contain ++ // removable prefixes ++ if ((removable_prefixes_zero > 0) && (removable_prefixes_one > 0)) { ++ // initialize auxiliar variables ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ int d = 1; // divisor of zero_weight and one_weight ++ int x = 0; // to be removed prefixes from zero subtree ++ int y = 0; // to be removed prefixes from one subtree ++ // find x and y such that ++ // a) x <= removable_prefixes_zero ++ // b) y <= removable_prefixes_one ++ // where ++ // x = zero_weight - (zero_weight / gcd) ++ // y = one_weight - (one_weight / gcd) ++ // and gcd is the gratest common divisor of zero_weight and one_weight ++ while ((d <= zero_weight) && (d <= one_weight)) { ++ // if d is the gcd ++ if (((zero_weight % d) == 0) && ((one_weight % d) == 0)) { ++ // if to be removed prefixes from both zero and one subtrees is ++ // smaller than removable prefixes from these subtrees ++ if ((zero_weight - zero_weight / d <= removable_prefixes_zero) ++ && ++ (one_weight - one_weight / d <= removable_prefixes_one)) { ++ x = zero_weight - (zero_weight / d); ++ y = one_weight - (one_weight / d); ++ } else { ++ break; ++ } ++ } ++ d++; ++ } ++ // return the total number of prefixes that can be removed without ++ // altering the skew ++ return removable_prefixes_this + ++ x + ++ y; ++ } else { ++ return removable_prefixes_this; ++ } ++ } else { ++ return removable_prefixes_this + ++ removable_prefixes_zero + ++ removable_prefixes_one; ++ } ++} // end get_removable_prefixes ++ ++ ++void Trie::adjust_node_skew(trie_node* node, float target_skew) { ++ // initialize lighter_* and heavier_* variables ++ int lighter_weight; ++ int heavier_weight; ++ trie_node* lighter_subtree; ++ trie_node* heavier_subtree; ++ // initialize auxiliary variables for skew computation ++ float skew; ++ int zero_weight = node->zero_weight; ++ int one_weight = node->one_weight; ++ // compute skew of the given node and set lighter_* and heavier_* variables ++ if (zero_weight > one_weight) { // zero subtree is heavier ++ skew = 1 - ((float)one_weight / (float)zero_weight); ++ lighter_weight = one_weight; ++ heavier_weight = zero_weight; ++ lighter_subtree = node->one; ++ heavier_subtree = node->zero; ++ } else { // one subtree is heavier ++ skew = 1 - ((float)zero_weight / (float)one_weight); ++ lighter_weight = zero_weight; ++ heavier_weight = one_weight; ++ lighter_subtree = node->zero; ++ heavier_subtree = node->one; ++ } ++ // initialize auxiliary variables ++ double new_weight_real; ++ int weight; ++ trie_node* subtree; ++ // decrease working skew - remove prefixes from heavier subtree ++ if ((skew - target_skew) > 0) { ++ new_weight_real = lighter_weight / (1 - target_skew); ++ weight = heavier_weight; ++ subtree = heavier_subtree; ++ // increase working skew - remove prefixes from lighter subtree ++ } else { ++ new_weight_real = heavier_weight * (1 - target_skew); ++ weight = lighter_weight; ++ subtree = lighter_subtree; ++ } ++ // determine new integer weight of a selected subtree ++ int new_weight = round(new_weight_real); ++ // determine number of prefixes that will be removed ++ int remove_prefixes = weight - new_weight; ++ int removable_prefixes = get_removable_prefixes(subtree); ++ if (remove_prefixes > removable_prefixes) { ++ // decrease the number of removed prefixes to the maximum number of ++ // prefixes that can be removed ++ remove_prefixes = removable_prefixes; ++ } ++ // make the selected subtree lighter by removing the given number of ++ //prefixes ++ make_subtree_lighter(subtree, remove_prefixes); ++ compute_weights(node); ++ return; ++} // end adjust_node_skew() ++ ++ ++void Trie::make_subtree_lighter(trie_node* root, int remove_prefixes) { ++ // nothing to do when the subtree is empty or 0 prefixes are to be removed ++ if ((root == NULL) || (remove_prefixes == 0)) { ++ return; ++ } ++ // auxiliary variables for counting statistics ++ trie_node* node = root; ++ int removable_prefixes_node = 0; ++ int removable_prefixes_branch = 0; ++ // in priority queue, nodes with less prefixes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_prefixes> pq; ++ // initialize auxiliary variables (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch = removable_prefixes_node; ++ pq.push(node); ++ } ++ // traverse a non-branching part of the subtree (i.e. up to the closest ++ // 2-children node or a leaf node) and compute basic statistics about it ++ while (((node->zero == NULL) && (node->one != NULL)) || ++ ((node->zero != NULL) && (node->one == NULL))) { ++ // determine the next step ++ if (node->zero == NULL) { ++ node = node->one; ++ } else { ++ node = node->zero; ++ } ++ // compute statistics (keep at least one prefix in a leaf node) ++ removable_prefixes_node = node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ if (removable_prefixes_node > 0) { ++ removable_prefixes_branch += removable_prefixes_node; ++ pq.push(node); ++ } ++ } ++ // get the number of removable prefixes in the remaining subtree ++ int removable_prefixes_subtree = get_removable_prefixes(node); ++ int removable_prefixes_zero = 0; ++ // adjust it to not contain removable prefixes of the subtree's root node ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_subtree = 0; ++ } else { ++ removable_prefixes_subtree -= node->prefixes; ++ } ++ // get the number of removable prefixes in branches of the remaining subtree ++ if (removable_prefixes_subtree > 0) { ++ int subtree_weight = node->zero_weight + node->one_weight; ++ removable_prefixes_zero = ++ round(((float)node->zero_weight / (float)subtree_weight) * ++ removable_prefixes_subtree); ++ } ++ // do not continue when no removable prefixes in the branch nor the subtree ++ if ((removable_prefixes_branch + removable_prefixes_subtree) == 0) { ++ return; ++ } ++ // distribute prefixes that are to be removed between the branch and the ++ // subtree ++ int remove_prefixes_branch = round(((float)removable_prefixes_branch / ++ (float)(removable_prefixes_subtree + ++ removable_prefixes_branch)) * ++ remove_prefixes); ++ int remove_prefixes_subtree = remove_prefixes - remove_prefixes_branch; ++ // initialize auxiliary variable for test purposes ++ int removed_prefixes_branch = 0; ++ // while there are some prefix nodes in the branch, remove prefixes ++ // proportionally from all these nodes ++ while (!pq.empty()) { ++ // deque the front element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // determine the number of prefixes that are to be removed from this node ++ int remove_prefixes_node; ++ if (!pq.empty()) { // not the last node of the branch ++ // keep at least one prefix in a leaf node ++ removable_prefixes_node = working_node->prefixes; ++ if ((node->zero == NULL) && (node->one == NULL)) { ++ removable_prefixes_node--; ++ } ++ // the nuber of prefixes to be removed is computed proportionally ++ remove_prefixes_node = round(((float)removable_prefixes_node / ++ (float)removable_prefixes_branch) * ++ remove_prefixes_branch); ++ } else { // the last node of the branch ++ // the number of prefixes to be removed ensures removing all the remaining prefixes ++ remove_prefixes_node = remove_prefixes_branch - removed_prefixes_branch; ++ } ++ // remove the given number of prefixes ++ working_node->prefixes -= remove_prefixes_node; ++ // adjust the test variable ++ removed_prefixes_branch += remove_prefixes_node; ++ } ++ // the last node in the non-branching part of the subtree is a 2-children ++ // node ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ // there are some prefixes to be removed from the subtree rooted at node ++ if (remove_prefixes_subtree > 0) { ++ // distribute prefixes that are to be removed from from the subtree ++ // between its zero and one subtrees ++ int remove_prefixes_zero = round(((float)removable_prefixes_zero / ++ (float)removable_prefixes_subtree) * ++ remove_prefixes_subtree); ++ int remove_prefixes_one = remove_prefixes_subtree - ++ remove_prefixes_zero; ++ // remove prefixes from subtrees of the 2-children node ++ compute_weights(node); ++ make_subtree_lighter(node->zero, remove_prefixes_zero); ++ make_subtree_lighter(node->one, remove_prefixes_one); ++ compute_weights(node); ++ } ++ } ++ return; ++} // end make_subtree_lighter() ++ ++ ++trie_node* Trie::remove_nonprefix_branches(trie_node* node) { ++ if (node != NULL) { // non-empty subtree ++ node->zero = remove_nonprefix_branches(node->zero); ++ node->one = remove_nonprefix_branches(node->one); ++ if ((node->zero == NULL) && (node->one == NULL) && ++ (node->prefixes == 0)) { ++ delete node; ++ return NULL; ++ } ++ } ++ return node; ++} //end remove_nonprefix_branches() ++ ++ ++void Trie::adjust_branching(vector branching_one_child, ++ vector branching_two_children) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // recursively compute weight of all subtrees ++ compute_weights(root); ++ // recursively compute maximum prefix nesting ++ int prefix_nesting = get_prefix_nesting(root); ++ // mark branches with maximum prefix nesting ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = -1; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // get pointer to the front element ++ trie_node* node = q.front(); ++ // first node at this level - perform branching adjustment ++ // (all nodes from the current level are enqueued) ++ if (node->level != level) { ++ level = node->level; ++ // compute branching statistics for this level ++ queue q_copy (q); ++ int one_child = 0; ++ int two_children = 0; ++ int sum = 0; ++ while (!q_copy.empty()) { ++ // dequeue front element from the auxiliary queue ++ trie_node* node_copy = q_copy.front(); ++ q_copy.pop(); ++ // increment correct counter ++ if ((node_copy->zero != NULL) && (node_copy->one != NULL)) { ++ two_children++; ++ } else if ((node_copy->zero != NULL) || (node_copy->one != NULL)) { ++ one_child++; ++ } ++ } ++ sum = one_child + two_children; ++ // branching probabilities are defined at this level ++ if (sum != 0) { // there is some branching at this level ++ float current_branching_two = (float) two_children / (float) (sum); ++ // adjust branching by reducing the number of two-children nodes ++ if (current_branching_two > branching_two_children[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = two_children - ++ (branching_two_children[level] * sum); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((two_children - floor(remove_subtrees)) / sum) ++ - branching_two_children[level]; ++ float diff_max = branching_two_children[level] - ++ ((two_children - ceil(remove_subtrees)) / sum); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, false, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ // adjust branching nodes count variables ++ one_child += remove_steps; ++ two_children -= remove_steps; ++ } ++ // removing subtree of one-child nodes can change branching ++ // probabilities ++ if (two_children != 0) { ++ float current_branching_one = (float) one_child / (float) (sum); ++ // adjust branching by reducing the number of one-child nodes ++ if (current_branching_one > branching_one_child[level]) { ++ // determine the ideal number of subtree removing steps ++ float remove_subtrees = ++ ((branching_one_child[level] * sum) - one_child) / ++ (branching_one_child[level] - 1); ++ // diff from ideal branching when remove min./max. subtrees ++ float diff_min = ((one_child - floor(remove_subtrees)) / ++ (sum - floor(remove_subtrees))) - ++ branching_one_child[level]; ++ float diff_max = branching_one_child[level] - ++ ((one_child - ceil(remove_subtrees)) / ++ (sum - ceil(remove_subtrees))); ++ // determine the number of subtree removing steps ++ int remove_steps = 0; ++ if (diff_min <= diff_max) { ++ remove_steps = (int) floor(remove_subtrees); ++ } else { ++ remove_steps = (int) ceil(remove_subtrees); ++ } ++ // remove the given number of "lightest" subtrees + ++ // actualize markers of maximum prefix nesting branches ++ for (int i = 0; i < remove_steps; i++) { ++ remove_lightest_subtree(q, true, ++ root->prefix_nesting_branches); ++ mark_prefix_nesting_branches(root, prefix_nesting, 0); ++ } ++ one_child -= remove_steps; ++ sum -= remove_steps; ++ } ++ } ++ } // end of if (sum != 0) ++ } // end of if (node->level != level) ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // remove the front element from the queue ++ q.pop(); ++ } // end of while (!q.empty()) ++ return; ++} // end adjust_branching() ++ ++ ++void Trie::adjust_skew(vector skew, float skew_epsilon) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // initialize auxiliary variables ++ queue q; ++ stack s; ++ q.push(root); ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element from the queue ++ trie_node* node = q.front(); ++ q.pop(); ++ // store nodes with 2 children into a stack ++ if ((node->zero != NULL) && (node->one != NULL)) { ++ s.push(node); ++ } ++ // enqueue possible successors of the current node ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ } ++ // initialize auxiliary variables ++ // in priority queue, lighter nodes have higher priority ++ priority_queue, ++ trie_nodes_greater_than_weight> pq; ++ float total_skew = 0.0; ++ int level; ++ if (!s.empty()) { ++ level = s.top()->level; ++ } ++ // do inverse breadth-first search on two-children nodes ++ while (!s.empty()) { ++ // pop top element from the stack ++ trie_node* node = s.top(); ++ s.pop(); ++ // next level - adjust total skew of the current level ++ if (level != node->level) { ++ // store the number of 2-children nodes at current level ++ int two_children_nodes = pq.size(); ++ // compute target total skew ("sum of all skew values at this level") ++ float target_total_skew = skew[level] * two_children_nodes; ++ // compute skew that is going to be added/removed ++ float skew_change = target_total_skew - total_skew; ++ // compute average skew that is going to be added/removed ++ float average_skew_change; ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ // iteratively adjust total skew at this level ++ while (!pq.empty()) { ++ // skip further skew adjustment when average_skew_change is less ++ // than the given skew_epsilon ++ if (abs(average_skew_change) < skew_epsilon) { ++ // remove remaining nodes from the priority queue ++ while (!pq.empty()) { ++ pq.pop(); ++ } ++ // end the outer "while (!pq.empty())" loop ++ break; ++ } ++ // pop the top element from the priority queue ++ trie_node* working_node = pq.top(); ++ pq.pop(); ++ // compute original skew of the working node ++ float original_skew = compute_skew(working_node); ++ float target_skew = original_skew + skew_change; ++ // adjust skew of the working node ++ if (target_skew < 0.0) { ++ target_skew = 0.0; ++ } else if (target_skew > 1.0) { ++ target_skew = 1.0; ++ } ++ adjust_node_skew(working_node, target_skew); ++ // recursively compute weight of node's subtrees ++ compute_weights(working_node); ++ // compute adjusted skew of the working node ++ float adjusted_skew = compute_skew(working_node); ++ // update total skew, skew that is going to be added/removed, and ++ // its average value ++ total_skew = total_skew - original_skew + adjusted_skew; ++ skew_change = target_total_skew - total_skew; ++ two_children_nodes = pq.size(); ++ if (two_children_nodes > 0) { ++ average_skew_change = skew_change / (float)two_children_nodes; ++ } else { ++ average_skew_change = skew_change; ++ } ++ } ++ level = node->level; ++ total_skew = 0.0; ++ } ++ // recursively compute weight of node's subtrees ++ compute_weights(node); ++ // insert the node into the priority queue ++ pq.push(node); ++ // actualize total skew value ++ total_skew += compute_skew(node); ++ } ++ return; ++} // end adjust_skew() ++ ++ ++void Trie::adjust_prefixes(vector prefixes_proportion, ++ const int target_size) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute the total number of prefixes at each level ++ vector all_prefixes(129,0); ++ queue q; ++ q.push(root); ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // update the total number of prefixes at current level ++ all_prefixes[node->level] += node->prefixes; ++ } ++ // compute the number of target and to be removed prefixes at each level ++ vector target_prefixes(129,0); ++ vector remove_prefixes(129,0); ++ int target_prefixes_total = 0; ++ int leaf_level = 0; ++ for (int i = 0; i < (int) prefixes_proportion.size(); i++) { ++ target_prefixes[i] = round(prefixes_proportion[i]*target_size); ++ target_prefixes_total += target_prefixes[i]; ++ remove_prefixes[i] = all_prefixes[i] - target_prefixes[i]; ++ if (target_prefixes[i] != 0) { ++ leaf_level = i; ++ } ++ } ++ // final correction to given target_size ++ if (target_prefixes_total != target_size) { ++ int diff = target_size - target_prefixes_total; ++ target_prefixes[leaf_level] += diff; ++ target_prefixes_total += diff; ++ remove_prefixes[leaf_level] -= diff; ++ } ++ // compute the number of prefixes to be removed at remaining levels ++ vector remove_prefixes_remaining(129,0); ++ for (int i = 127; i >= 0; i--) { ++ remove_prefixes_remaining[i] = remove_prefixes_remaining[i+1] + ++ remove_prefixes[i+1]; ++ } ++ // starting from the root, adjust prefixes distribution ++ queue nodes; ++ nodes.push(root); ++ queue remove_prefixes_subtrees; ++ remove_prefixes_subtrees.push(remove_prefixes[0] + remove_prefixes_remaining[0]); ++ int level = -1; ++ while (!nodes.empty()) { ++ // get the front element ++ // (from both nodes and remove_prefixes_subtrees queues) ++ trie_node* node = nodes.front(); ++ // next level - adjust prefixes at this level ++ // (all nodes of this level are stored in nodes queue) ++ if (node->level != level) { ++ level = node->level; ++ // actualize subtrees' weight information in nodes ++ compute_weights(root); ++ // initialize vectors to contain all current elements of queues ++ queue nodes_copy (nodes); ++ vector nodes_vect; ++ queue remove_prefixes_subtrees_copy (remove_prefixes_subtrees); ++ vector remove_prefixes_subtrees_vect; ++ while (!nodes_copy.empty()) { ++ nodes_vect.push_back(nodes_copy.front()); ++ nodes_copy.pop(); ++ remove_prefixes_subtrees_vect.push_back(remove_prefixes_subtrees_copy.front()); ++ remove_prefixes_subtrees_copy.pop(); ++ } ++ // from all leaf nodes at this level ++ // remove prefixes that have to be removed ++ int i = 0; ++ while (i < (int) nodes_vect.size()) { ++ if ((nodes_vect[i]->zero == NULL) && ++ (nodes_vect[i]->one == NULL)) { ++ // determine the real number of prefixes to be removed ++ // (do not remove the last prefix from a leaf node) ++ int remove_prefixes_node; ++ if (nodes_vect[i]->prefixes > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } else { ++ remove_prefixes_node = nodes_vect[i]->prefixes - 1; ++ } ++ // consider all prefixes of this node and this subtree to be ++ // removed, regardless they are really removed or not ++ // (in any case, there are no other prefixes that could be ++ // removed) ++ all_prefixes[level] -= nodes_vect[i]->prefixes; ++ remove_prefixes_subtrees_vect[i] = 0; ++ // remove the prefixes ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ // remove this node from both vectors ++ nodes_vect.erase(nodes_vect.begin()+i); ++ remove_prefixes_subtrees_vect.erase(remove_prefixes_subtrees_vect.begin()+i); ++ } else { ++ // the node has not been removed, thus increase the index ++ i++; ++ } ++ } ++ // if there are some nodes with prefixes that could be removed AND ++ // the number of prefixes to be removed is not negative ++ if ((all_prefixes[level] > 0) && (remove_prefixes[level] >= 0)) { ++ // initialize auxiliary constant (for this level) ++ float remove_all_ratio = (float)(remove_prefixes[level]) / ++ (float)(all_prefixes[level]); ++ // from all non-leaf nodes at this level ++ // remove prefixes that are to be removed at this level ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ int remove_prefixes_node = round((float)(nodes_vect[i]->prefixes) * ++ remove_all_ratio); ++ // do not remove more than all prefixes to be removed from this subtree ++ if (remove_prefixes_node > remove_prefixes_subtrees_vect[i]) { ++ remove_prefixes_node = remove_prefixes_subtrees_vect[i]; ++ } ++ // do not remove more than all prefixes of this node ++ if (remove_prefixes_node > nodes_vect[i]->prefixes) { ++ remove_prefixes_node = nodes_vect[i]->prefixes; ++ } ++ // remove the prefixes and adjust other variables ++ nodes_vect[i]->prefixes -= remove_prefixes_node; ++ all_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes[level] -= remove_prefixes_node; ++ remove_prefixes_subtrees_vect[i] -= remove_prefixes_node; ++ } ++ } ++ // for all nodes at this level ++ // distribute prefixes to be removed in a subtree rooted at this node ++ // into node's subtrees ++ for (int i = 0; i < (int) nodes_vect.size(); i++) { ++ // distribution for 2-children nodes ++ if ((nodes_vect[i]->zero != NULL) && (nodes_vect[i]->one != NULL)) { ++ // determine the distribution ++ int total_weight = nodes_vect[i]->zero_weight + ++ nodes_vect[i]->one_weight; ++ int remove_prefixes_zero = round(((float)(nodes_vect[i]->zero_weight) / ++ (float)total_weight) * ++ (float)(remove_prefixes_subtrees_vect[i])); ++ int remove_prefixes_one = remove_prefixes_subtrees_vect[i] - ++ remove_prefixes_zero; ++ // do not remove more than all prefixes from zero subtree ++ if (remove_prefixes_zero > nodes_vect[i]->zero_weight) { ++ remove_prefixes_zero = nodes_vect[i]->zero_weight; ++ } ++ // do not remove more than all prefixes from one subtree ++ if (remove_prefixes_one > nodes_vect[i]->one_weight) { ++ remove_prefixes_one = nodes_vect[i]->one_weight; ++ } ++ // store the distribution into main queues ++ nodes.push(nodes_vect[i]->zero); ++ remove_prefixes_subtrees.push(remove_prefixes_zero); ++ nodes.push(nodes_vect[i]->one); ++ remove_prefixes_subtrees.push(remove_prefixes_one); ++ } else { ++ // distribution for 1-child nodes ++ if (nodes_vect[i]->zero != NULL) { ++ nodes.push(nodes_vect[i]->zero); ++ } else if (nodes_vect[i]->one != NULL) { ++ nodes.push(nodes_vect[i]->one); ++ } ++ remove_prefixes_subtrees.push(remove_prefixes_subtrees_vect[i]); ++ } ++ } ++ } ++ // remove the front elements from the main queues ++ nodes.pop(); ++ remove_prefixes_subtrees.pop(); ++ } ++ return; ++} // end adjust_prefixes() ++ ++ ++// ***** Public functions ***************************************************** ++ ++ ++// Default constructor ++Trie::Trie() { ++ root = NULL; ++} // end Trie() ++ ++ ++// Copy constructor ++Trie::Trie(const Trie& orig) { ++ root = copy(orig.get_root(), 0); ++} // end Trie() ++ ++ ++// Destructor ++Trie::~Trie() { ++ destruct(root); ++} // end ~Trie() ++ ++ ++// Copy assignment ++Trie& Trie::operator= (const Trie& orig) { ++ // replace the original trie by a copy of the assigned trie ++ destruct(root); ++ root = copy(orig.get_root(), 0); ++ // return created object ++ return *this; ++} // end operator= () ++ ++ ++void Trie::insert(const IP_prefix& pref) { ++ // insert at least a root node when the trie is empty ++ if (root == NULL) { ++ root = new trie_node; ++ root->level = 0; ++ root->prefixes = 0; ++ root->prefix_nesting_branches = 0; ++ root->zero = NULL; ++ root->zero_weight = 0; ++ root->one = NULL; ++ root->one_weight = 0; ++ } ++ // insert the given prefix into the trie ++ if (pref.get_length() == 0) { // prefix of length 0 ++ (root->prefixes)++; ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** next_node_ptr; ++ string prefix = pref.get_prefix(); ++ // trie traversal ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node and store the pointer to it ++ if (prefix[i] == '0') { ++ next_node_ptr = &(node->zero); ++ } else { // (prefix[i] == '1') ++ next_node_ptr = &(node->one); ++ } ++ // insert the next node if it does not exist ++ if ((*next_node_ptr) == NULL) { ++ (*next_node_ptr) = new trie_node; ++ (*next_node_ptr)->level = i+1; ++ (*next_node_ptr)->prefixes = 0; ++ (*next_node_ptr)->prefix_nesting_branches = 0; ++ (*next_node_ptr)->zero = NULL; ++ (*next_node_ptr)->zero_weight = 0; ++ (*next_node_ptr)->one = NULL; ++ (*next_node_ptr)->one_weight = 0; ++ } ++ // move to the next node; ++ node = (*next_node_ptr); ++ } ++ // prefix insertion ++ (node->prefixes)++; ++ } ++ return; ++} // end insert() ++ ++ ++bool Trie::erase(const IP_prefix& pref) { ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return root; ++ } ++ // search for the given prefix ++ if (pref.get_length() == 0) { // prefix of length 0 ++ if (root->prefixes > 0) { // we have found the prefix node ++ (root->prefixes)--; ++ if ((root->prefixes == 0) && ++ (root->zero == NULL) && ++ (root->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(root); ++ root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } else { // prefix of length > 0 ++ // auxiliary variables ++ trie_node* node = root; ++ trie_node** destruct_root = &(root); ++ string prefix = pref.get_prefix(); ++ for (int i = 0; i < pref.get_length(); i++) { ++ // determine the next node ++ if (prefix[i] == '0') { ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->one != NULL)) { // this node cannot be removed ++ destruct_root = &(node->zero); ++ } ++ // move to the next node ++ node = node->zero; ++ } else { // (prefix[i] == '1') ++ // adjust desctruct_root ++ if ((node->prefixes != 0) || ++ (node->zero != NULL)) { // this node cannot be removed ++ destruct_root = &(node->one); ++ } ++ // move to the next node ++ node = node->one; ++ } ++ // chceck whether the next node exists (terminate search if not) ++ if (node == NULL) { ++ return false; ++ } ++ } ++ if (node->prefixes > 0) { // we have found the prefix node ++ (node->prefixes)--; ++ if ((node->prefixes == 0) && ++ (node->zero == NULL) && ++ (node->one == NULL)) { ++ // all the conditions for removing the node were met ++ destruct(*destruct_root); ++ *destruct_root = NULL; ++ } ++ return true; ++ } else { // the corresponding node is a non-prefix node ++ return false; ++ } ++ } ++} // end erase() ++ ++ ++void Trie::prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations) { ++ // get original prefix set size ++ trie_stats s; ++ this->get_stats(s); ++ int orig_size = s.classbench.prefixes; ++ ++ // adjust branching (1st step of trie pruning) ++ this->adjust_branching(one_child, two_children); ++ ++ // iteratively adjust skew and prefixes proportion ++ // (multiple iterations help to reduce the negative effect of ++ // adjust_prefixes function on skew) ++ for (int i = 1; i <= iterations; i++) { ++ // adjust skew (2nd step of trie pruning) ++ this->adjust_skew(skew); ++ // adjust prefixes proportion (3rd step of trie pruning) ++ if (i == iterations) { ++ this->adjust_prefixes(prefixes, target_size); ++ } else { ++ this->adjust_prefixes(prefixes, round((1-(float)i/4)*orig_size)); ++ } ++ } ++} // end prune() ++ ++ ++void Trie::get_stats(trie_stats& stats) { ++ // initialize classbench statistics ++ stats.classbench.prefixes = 0; ++ stats.classbench.prefix_lengths = vector(129,0); ++ stats.classbench.branching_one_child = vector(129,0.0); ++ stats.classbench.branching_two_children = vector(129,0.0); ++ stats.classbench.skew = vector(129,0.0); ++ stats.classbench.prefix_nesting = 0; ++ // initialize nodes statistics ++ stats.nodes.leaf = vector(129,0); ++ stats.nodes.one_child = vector(129,0); ++ stats.nodes.two_children = vector(129,0); ++ stats.nodes.prefix = vector(129,0); ++ stats.nodes.non_prefix = vector(129,0); ++ // nothing to do when the trie is empty ++ if (root == NULL) { ++ return; ++ } ++ // compute zero_weight and one_weight in each node of the trie ++ compute_weights(root); ++ // initialize auxiliary variables ++ queue q; ++ q.push(root); ++ int level = root->level; ++ // do a breadth-first search ++ while (!q.empty()) { ++ // dequeue front element ++ trie_node* node = q.front(); ++ q.pop(); ++ // enqueue its possible successors ++ if (node->zero != NULL) { ++ q.push(node->zero); ++ } ++ if (node->one != NULL) { ++ q.push(node->one); ++ } ++ // level change - finish statistics computation for the previous level ++ if (node->level != level) { ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // increment the level counter ++ level++; ++ } ++ // trie node visit - classbench statistics ++ stats.classbench.prefixes += node->prefixes; ++ stats.classbench.prefix_lengths[level] += node->prefixes; ++ if ((node->zero != NULL) && (node->one != NULL)) { // skew is defined ++ stats.classbench.skew[level] += compute_skew(node); ++ } ++ // trie node visit - nodes statistics ++ if (node->zero == NULL) { ++ if (node->one == NULL) { // leaf node ++ (stats.nodes.leaf[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } else { // node->zero != NULL ++ if (node->one != NULL) { // two child node ++ (stats.nodes.two_children[level])++; ++ } else { // one child node ++ (stats.nodes.one_child[level])++; ++ } ++ } ++ if (node->prefixes > 0) { // prefix node ++ (stats.nodes.prefix[level])++; ++ } else { // non-prefix node ++ (stats.nodes.non_prefix[level])++; ++ } ++ } // end of while (!q.empty()) ++ // finish statistics computation for the last level ++ // auxiliary variables ++ int one_child = stats.nodes.one_child[level]; ++ int two_children = stats.nodes.two_children[level]; ++ int sum = one_child + two_children; ++ // branching_one_child and branching_two_children ++ if (sum != 0) { ++ stats.classbench.branching_one_child[level] = ++ (float)one_child / (float)sum; ++ stats.classbench.branching_two_children[level] = ++ (float)two_children / (float)sum; ++ } ++ // skew ++ if (two_children != 0) { ++ stats.classbench.skew[level] /= (float)two_children; ++ } ++ // compute prefix nesting ++ stats.classbench.prefix_nesting = get_prefix_nesting(root); ++ return; ++} // end get_stats() +diff --git a/trie.h b/trie.h +new file mode 100644 +index 0000000..4cbe414 +--- /dev/null ++++ b/trie.h +@@ -0,0 +1,477 @@ ++// trie.h: header file for trie class ++// ++// Jiri Matousek, 2014 ++// imatousek@fit.vutbr.cz ++ ++ ++#ifndef TRIE_H ++#define TRIE_H ++ ++ ++// User includes ++#include "ip_prefix.h" ++ ++// Library includes ++#include ++#include ++ ++// Default namespace ++using namespace std; ++ ++ ++// **************************************************************************** ++// Structures declaration ++// **************************************************************************** ++ ++/* ++ * Structure representing a node of a trie. ++ * ++ * Each node can be a prefix node (prefixes > 0) or a non-prefix node ++ * (prefixes = 0) and it can have at most two successors accessible using ++ * pointers zero (when the next bit of the prefix is 0) or one (when the next ++ * bit of the prefix is 1). ++ * Except these basic members, each trie node stores some other values that ++ * make the computation of trie characteristics easier. These values are ++ * further described directly in the trie node structure declaration. ++ */ ++ ++struct trie_node { ++ // trie level (i.e. distance from the root) at which the node resides ++ int level; ++ ++ // number of occurences of the prefix ++ int prefixes; ++ ++ // counter of branches with maximum prefix nesting that this node is part of ++ int prefix_nesting_branches; ++ ++ // 0-subtree-related members ++ trie_node* zero; // pointer to the subtree root ++ int zero_weight; // number of prefixes in the subtree ++ ++ // 1-subtree-related members ++ trie_node* one; // pointer to the subtree root ++ int one_weight; // number of prefixes in the subtree ++}; ++ ++/* ++ * Structure representing trie statistics proposed in the ClassBench tool. ++ * ++ * Vector members store statistics defined separately for each level of the ++ * trie. Prefix nesting is defined for the whole trie. ++ */ ++struct classbench_stats { ++ // total number of prefixes ++ int prefixes; ++ ++ // number of prefixes (not prefix nodes) with given length ++ vector prefix_lengths; ++ ++ // probability of node with only one child (from all non-leaf nodes) ++ vector branching_one_child; ++ // probability of node with two children (from all non-leaf nodes) ++ vector branching_two_children; ++ ++ // average relative weight ratio of lighter vs heavier subtree ++ // (nodes with two children only) ++ vector skew; ++ ++ // maximum number of prefix nodes on an arbitrary path in the trie ++ int prefix_nesting; ++}; ++ ++/* ++ * Structure representing statistics related to trie nodes. ++ * ++ * All the statistics are stored separately for each level of the trie. ++ */ ++struct node_stats { ++ vector leaf; // number of leaf nodes ++ vector one_child; // number of nodes with one child only ++ vector two_children; // number of nodes with both children ++ vector prefix; // number of prefix nodes (not prefixes) ++ vector non_prefix; // number of non-prefix nodes ++}; ++ ++/* ++ * Structure representing statistics related to the trie. ++ * ++ * Statistics are divided into two groups: ++ * 1) statistics proposed in ClassBench tool and ++ * 2) statistics related to trie nodes. ++ */ ++struct trie_stats { ++ classbench_stats classbench; // ClassBench statistics ++ node_stats nodes; // nodes statistics ++}; ++ ++// **************************************************************************** ++// Class declaration ++// **************************************************************************** ++ ++/* ++ * Class for representation of a binary prefix tree - trie. ++ * ++ * Class functions do not adjust zero_weight and one_weight counters in a trie ++ * node by default. These feilds are viewed as place holders and they can be ++ * set to the correct value by calling the compute_weights(). ++ */ ++class Trie { ++ private: ++ /* ++ * Pointer to the root node of the trie. ++ */ ++ trie_node* root; ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++// (MAYBE JUST ONE REASON -- BY COPYING ONLY A SUBTREE YOU LOOSE THE ++// INFORMATION ABOUT THE COMMON PREFIX, I.E. PATH IN TRIE PRECEDING THIS ++// SUBTREE) ++ /* ++ * Private static function for copying a subtree of the trie, where the ++ * subtree is specified by a pointer to its root node. ++ * Trie node members prefixes, zero_weight, and one_weight are copied ++ * without any change, while the level member is set to the given value. ++ * This approach allows e.g. to create a new valid trie by copying the ++ * given subtree. (In such a case the level parameter have to be set to ++ * 0 during the initial function call.) ++ * Trie node members zero and one are set to the values returned by the ++ * recursive call of the copy() onto the 0-subtree and 1-subtree, ++ * respectively. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * copied. ++ * @param level Value for the level member of the copied trie node. ++ * @return Pointer to the root node of the copy. ++ */ ++ static trie_node* copy(const trie_node* node, int level); ++ ++ /* ++ * Private static function for destruction of a trie's subtree. The ++ * subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of a subtree that is to be ++ * destructed. ++ */ ++ static void destruct(trie_node* node); ++ ++ /* ++ * Private static function for computation of zero_weight and one_weight ++ * values of all the trie nodes in a given subtree. The subtree is given ++ * by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * weights are to be computed. ++ * @return Weights of the given subtree. ++ */ ++ static int compute_weights(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of node's skew as defined in ++ * the ClassBench paper. This function expects that the pointed node is ++ * a 2-children node and that its fields zero_weight and one_weight ++ * contain valid values. ++ * @param node Pointer to the node of which the skew is going to be ++ * computed. ++ * @return Skew of the given node. ++ */ ++ static float compute_skew(trie_node* node); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function that determines the maximum prefix nesting in ++ * a given subtree, i.e. the maximum number of prefixes on any path from ++ * the root to the leaves in the subtree. The subtree is given by a ++ * pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which the ++ * prefix nesting is to be computed. ++ * @return Maximum prefix nesting in the given subtree. ++ */ ++ static int get_prefix_nesting(const trie_node* node); ++ ++ /* ++ * Private static function that removes the lightest subtree among trie ++ * nodes passed in a queue. The lightest subtree can be selected ++ * either among one-child nodes or two-children nodes. The selection is ++ * done in such a way that when the lightest subtree is removed, there ++ * is still at least one branch with maximum prefix nesting in the trie. ++ * After removing the lightest subtree, corresponding subtree weight is ++ * set to 0. ++ * @param q Queue with trie nodes that are to be ++ * inspected. ++ * @param one_child Select lightest subtree either among ++ * one-child nodes (TRUE) or ++ * two-children nodes (FALSE). ++ * @param prefix_nesting_branches The number of branches in the trie ++ * with maximum prefix nesting. ++ */ ++ static void remove_lightest_subtree(queue q, bool one_child, ++ int prefix_nesting_branches); ++ ++ /* ++ * Private static function for marking branches with maximum prefix ++ * nesting in a given subtree. The subtree is given by a pointer to its ++ * root node. Maximum prefix nesting is specified as a parameter of the ++ * function (therefore, it has to be computed outside the function). ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in ++ * which prefix nesting branches are to be ++ marked. ++ * @param prefix_nesting Maximum prefix nesting in the given subtree. ++ * @param seen_prefixes Number of prefixes that has been seen so far. ++ * @return Weights of the given subtree. ++ */ ++ static int mark_prefix_nesting_branches(trie_node* node, ++ int prefix_nesting, ++ int seen_prefixes); ++ ++// PROBABLY IT IS NOT NECESSARY TO HAVE THIS FUNCTION PRIVATE ++ /* ++ * Private static function for computation of the maximum number of ++ * prefixes that can be removed from a given subtree. When computing the ++ * result of this function, the following contraints are taken into ++ * account: ++ * * no prefix node within the subtree must not become a non-prefix ++ * node after removing the prefixes; ++ * * removing the prefixes from subtrees of 2-children node should not ++ * alter the skew of this node. ++ * The subtree is given by a pointer to its root node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node A Pointer to the root node of the subtree in which the ++ number of removable prefixes is going to be computed. ++ * @return The number of removable prefixes in the given subtree. ++ */ ++ static int get_removable_prefixes(trie_node* node); ++ ++ /* ++ * Private static function for adjusting skew of a specified node to the ++ * given value. The node is specified by it's pointer and the target ++ * skew is given as a float number. ++ * @param node Pointer to the node whose skew is going to be ++ * adjusted. ++ * @param target_skew The value to which the node's skew should be ++ * adjusted. ++ */ ++ static void adjust_node_skew(trie_node* node, float target_skew); ++ ++ /* ++ * Private static function that removes the given number of prefixes from ++ * a subtree specified by the pointer to its root node. Prefixes are ++ * removed as equally as possible while following a rule that no prefix ++ * node can be turned to a non-prefix node. Removing of prefixes is ++ * performed over all prefix nodes from the root node up to the closest ++ * 2-children node or a leaf node... ++ * @param root Pointer to the root node of the subtree in which ++ * prefixes are going to be removed. ++ * @remove_prefixes The number of prefixes that should be removed from ++ * the specified subtree. ++ */ ++ static void make_subtree_lighter(trie_node* root, int remove_prefixes); ++ ++ /* ++ * Private static function for removing branches without a prefix node ++ * from a given subtree. The subtree is given by a pointer to its root ++ * node. ++ * CAUTION: ++ * * This function uses recursive calls! ++ * @param node Pointer to the root node of the subtree in which ++ * nonprefix are to be removed. ++ * @return actualized pointer to the subtree's root node ++ * (NULL when the whole subtree was removed) ++ */ ++ static trie_node* remove_nonprefix_branches(trie_node* node); ++ ++ /* ++ * Private function that removes some subtrees in order to achieve ++ * branching probabilities that are as close as possible to the given ++ * values. ++ * Modifications are done on a per level basis, starting from the root ++ * node. Changes at each level are done in two steps: ++ * 1) lightest subtrees of two-children nodes are removed to achieve ++ * given branching_two_children probability ++ * 2) lightest subtrees of one-child nodes are removed to achieve ++ * given branching_one_child probability ++ * @param branching_one_child Vector specifying probability of ++ * occurence of a trie node with one ++ * child at the given level of the trie. ++ * @param branching_two_children Vector specifying probability of ++ * occurence of a trie node with two ++ * children at the given level of the ++ * trie. ++ */ ++ void adjust_branching(vector branching_one_child, ++ vector branching_two_children); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve an ++ * average skew that is as close as possible to the given values for ++ * particular levels. ++ * Prefixes are removed on a per level basis, starting from the lowest ++ * level. At each level, an average skew is increased/decreased by ++ * removing prefixes from lighter/heavier subtree of the level's nodes. ++ * This adjustment starts from nodes with the lightest subtrees ++ * (adjusting their skew requires removing of the lowest number of ++ * prefixes) and it is implemented such that it (almost) does not change ++ * a skew of nodes at lower levels. ++ * @param skew Vector specifying an average skew at all levels of ++ * the trie. ++ * @ skew_epsilon Threshold value for average skew change at not yet ++ * adjusted nodes (skew adjustment stops when average ++ * skew change is less than the given skew_epsilon). ++ */ ++ void adjust_skew(vector skew, float skew_epsilon = 0.01); ++ ++ /* ++ * Private function that removes some prefixes in order to achieve ++ * prefixes distribution that is as close as possible to the given values ++ * for particular levels. ++ * Prefixes are removed on a per level basis, starting from the root ++ * node. Removing the prefixes consists of three steps: ++ * 1) removing the prefixes from leaf nodes (the last prefix ++ * represented by a leaf node is never removed) ++ * 2) removing the prefixes from non-leaf nodes, proportionally to ++ * their weight ++ * 3) distributing prefixes that are to be removed at lower levels to ++ * subtrees of non-leaf nodes (this distribution is driven by skew) ++ * @param prefixes_proportion Vector that for all trie levels specifies ++ * proportion of prefixes at the given level ++ * to all prefixes in the trie. ++ * @param target_size Target total number of prefixes in the ++ * trie. ++ */ ++ void adjust_prefixes(vector prefixes_proportion, ++ const int target_size); ++ ++ public: ++ /* ++ * Default constructor. ++ * Pointer to the root node is initialized to NULL. ++ */ ++ Trie(); ++ ++ /* ++ * Copy constructor. ++ * Pointer to the root node is initialized by the result of the private ++ * copy(). ++ * @param orig Reference to the original trie object. ++ */ ++ Trie(const Trie& orig); ++ ++ /* ++ * Destructor. ++ * Trie specified by the root pointer is destructed by the private ++ * destruct(). ++ */ ++ ~Trie(); ++ ++ /* ++ * Copy assignment. ++ * Original trie is destructed by the private destruct() and the new trie ++ * is created by the private copy(). ++ * @param orig Reference to the original trie object. ++ * @return Reference to the new trie object. ++ */ ++ Trie& operator= (const Trie& orig); ++ ++ /* ++ * Get function for the root pointer. ++ * @return Pointer to the root node of the trie. ++ */ ++ inline const trie_node* get_root() const { ++ return root; ++ } // end get_root() ++ ++ /* ++ * Inserts the specified prefix into the trie. ++ * The trie is non-recursively traversed to the corresponding trie node, ++ * where the prefix is newly inserted or at least the counter of its ++ * occurences is incremented. ++ * All the missing nodes on a way to the prefix node are newly created ++ * and inserted into the trie as non-prefix nodes. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be inserted. ++ */ ++ void insert(const IP_prefix& pref); ++ ++ /* ++ * Erases the specified prefix from the trie. ++ * The prefix is searched by non-recursively traversing the trie. If the ++ * erase() finds the prefix, the counter of its occurences is decremented ++ * and return value is set to TRUE. ++ * If the erased prefix was the last one (i.e. prefix node has changed to ++ * non-prefix node) and there is not more specific prefix (i.e. prefix ++ * node is a leaf node of the trie), its corresponding node and all its ++ * non-prefix predecessors (up to the closest node with two children) are ++ * removed from the trie using private destruct(). ++ * If the erase() does not find the prefix, it silently ends without any ++ * further action and with return value set to FALSE. ++ * @param pref Reference to the IP_prefix object representing the ++ * prefix that is to be removed. ++ * @return TRUE if the prefix was removed, ++ * FALSE otherwise. ++ */ ++ bool erase(const IP_prefix& pref); ++ ++ /* ++ * Prunes the trie in order to achieve the given characteristics. ++ * The function first adjusts branching probability distributions at all ++ * trie levels. Next, average skew and prefix length distributions are ++ * adjusted while the number of prefixes in the trie is iteratively ++ * decreased towards the given target size. ++ * @param target_size Target number of prefixes in the trie. The ++ * final number of prefixes in the pruned trie can ++ * be slightly different. ++ * @param prefixes The vector of target prefix length distribution ++ * over the trie levels. ++ * @param one_child The vector of target one-child branching ++ * probability distribution over the trie levels. ++ * @param two_children The vector of target two-children branching ++ * probability distribution over the trie levels. ++ * @param skew The vector of target average skew distribution ++ * over the trie levels. ++ * @param iterations The number of iterations of average skew and ++ * prefix length distribution adjustment. ++ */ ++ void prune(const int target_size, ++ const vector& prefixes, ++ const vector& one_child, ++ const vector& two_children, ++ const vector& skew, ++ const int iterations = 4); ++ ++ /* ++ * Computes all defined trie statistics and stores them into a given ++ * structure. ++ * Except prefix nesting, which is computed during separate recursive ++ * traversal, all the other statistics are computed during single ++ * breadth-first search. Following statistics are actualized when ++ * visiting the nodes: ++ * * classbench.prefix_lengths ++ * * classbench.skew ++ * * nodes.leaf ++ * * nodes.one_child ++ * * nodes.two_children ++ * * nodes.prefix ++ * * nodes.non_prefix ++ * The value classbech.skew is also adjusted (divided by ++ * nodes.two_children) after visiting all the nodes at the current trie ++ * level. ++ * There are also two statistics (classbench.branching_one_child and ++ * classbench.branching_two_children) that are fully computed after ++ * visiting all the nodes at the current trie level. Their computation is ++ * based on values nodes.one_child and nodes.two_children. ++ * @param stats Reference to a data structure for computed trie ++ * statistics. ++ */ ++ void get_stats(trie_stats& stats); ++}; ++ ++#endif +diff --git a/uint128_t.cc b/uint128_t.cc +new file mode 100644 +index 0000000..1e16bbd +--- /dev/null ++++ b/uint128_t.cc +@@ -0,0 +1,372 @@ ++#include "uint128_t.h" ++ ++const uint128_t uint128_0(0); ++const uint128_t uint128_1(1); ++const uint128_t uint128_64(64); ++const uint128_t uint128_128(128); ++ ++uint128_t::uint128_t(){ ++ UPPER = 0; ++ LOWER = 0; ++} ++ ++uint128_t::uint128_t(const uint128_t & rhs){ ++ UPPER = rhs.UPPER; ++ LOWER = rhs.LOWER; ++} ++ ++uint128_t uint128_t::operator=(const uint128_t & rhs){ ++ UPPER = rhs.UPPER; ++ LOWER = rhs.LOWER; ++ return *this; ++} ++ ++uint128_t::operator bool() const{ ++ return (bool) (UPPER | LOWER); ++} ++ ++uint128_t::operator char() const{ ++ return (char) LOWER; ++} ++uint128_t::operator int() const{ ++ return (int) LOWER; ++} ++ ++uint128_t::operator uint8_t() const{ ++ return (uint8_t) LOWER; ++} ++ ++uint128_t::operator uint16_t() const{ ++ return (uint16_t) LOWER; ++} ++ ++uint128_t::operator uint32_t() const{ ++ return (uint32_t) LOWER; ++} ++ ++uint128_t::operator uint64_t() const{ ++ return (uint64_t) LOWER; ++} ++ ++uint128_t uint128_t::operator&(const uint128_t & rhs) const{ ++return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator|(const uint128_t & rhs) const{ ++ return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator^(const uint128_t & rhs) const{ ++ return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator&=(const uint128_t & rhs){ ++ UPPER &= rhs.UPPER; ++ LOWER &= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator|=(const uint128_t & rhs){ ++ UPPER |= rhs.UPPER; ++ LOWER |= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator^=(const uint128_t & rhs){ ++ UPPER ^= rhs.UPPER; ++ LOWER ^= rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator~() const{ ++ return uint128_t(~UPPER, ~LOWER); ++} ++ ++uint128_t uint128_t::operator<<(const uint128_t & rhs) const{ ++ uint64_t shift = rhs.LOWER; ++ if (((bool) rhs.UPPER) || (shift >= 128)){ ++ return uint128_0; ++ } ++ else if (shift == 64){ ++ return uint128_t(LOWER, 0); ++ } ++ else if (shift == 0){ ++ return *this; ++ } ++ else if (shift < 64){ ++ return uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift); ++ } ++ else if ((128 > shift) && (shift > 64)){ ++ return uint128_t(LOWER << (shift - 64), 0); ++ } ++ else{ ++ return uint128_0; ++ } ++} ++ ++uint128_t uint128_t::operator>>(const uint128_t & rhs) const{ ++ uint64_t shift = rhs.LOWER; ++ if (((bool) rhs.UPPER) || (shift >= 128)){ ++ return uint128_0; ++ } ++ else if (shift == 64){ ++ return uint128_t(0, UPPER); ++ } ++ else if (shift == 0){ ++ return *this; ++ } ++ else if (shift < 64){ ++ return uint128_t(UPPER >> shift, (UPPER << (64 - shift)) + (LOWER >> shift)); ++ } ++ else if ((128 > shift) && (shift > 64)){ ++ return uint128_t(0, (UPPER >> (shift - 64))); ++ } ++ else{ ++ return uint128_0; ++ } ++} ++ ++uint128_t uint128_t::operator<<=(const uint128_t & rhs){ ++ *this = *this << rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator>>=(const uint128_t & rhs){ ++ *this = *this >> rhs; ++ return *this; ++} ++ ++bool uint128_t::operator!() const{ ++ return !(bool) (UPPER | LOWER); ++} ++ ++bool uint128_t::operator&&(const uint128_t & rhs) const{ ++ return ((bool) *this && rhs); ++} ++ ++bool uint128_t::operator||(const uint128_t & rhs) const{ ++ return ((bool) *this || rhs); ++} ++ ++bool uint128_t::operator==(const uint128_t & rhs) const{ ++ return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER)); ++} ++ ++bool uint128_t::operator!=(const uint128_t & rhs) const{ ++ return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER)); ++} ++ ++bool uint128_t::operator>(const uint128_t & rhs) const{ ++ if (UPPER == rhs.UPPER){ ++ return (LOWER > rhs.LOWER); ++ } ++ return (UPPER > rhs.UPPER); ++} ++ ++bool uint128_t::operator<(const uint128_t & rhs) const{ ++ if (UPPER == rhs.UPPER){ ++ return (LOWER < rhs.LOWER); ++ } ++ return (UPPER < rhs.UPPER); ++} ++ ++bool uint128_t::operator>=(const uint128_t & rhs) const{ ++ return ((*this > rhs) | (*this == rhs)); ++} ++ ++bool uint128_t::operator<=(const uint128_t & rhs) const{ ++ return ((*this < rhs) | (*this == rhs)); ++} ++ ++uint128_t uint128_t::operator+(const uint128_t & rhs) const{ ++ return uint128_t(UPPER + rhs.UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator+=(const uint128_t & rhs){ ++ UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER); ++ LOWER += rhs.LOWER; ++ return *this; ++} ++ ++uint128_t uint128_t::operator-(const uint128_t & rhs) const{ ++ return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER); ++} ++ ++uint128_t uint128_t::operator-=(const uint128_t & rhs){ ++ *this = *this - rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator*(const uint128_t & rhs) const{ ++ // split values into 4 32-bit parts ++ uint64_t top[4] ={UPPER >> 32, UPPER & 0xffffffff, LOWER >> 32, LOWER & 0xffffffff}; ++ uint64_t bottom[4] ={rhs.UPPER >> 32, rhs.UPPER & 0xffffffff, rhs.LOWER >> 32, rhs.LOWER & 0xffffffff}; ++ uint64_t products[4][4]; ++ ++ for(int y = 3; y > -1; y--){ ++ for(int x = 3; x > -1; x--){ ++ products[3 - x][y] = top[x] * bottom[y]; ++ } ++ } ++ ++ // initial row ++ uint64_t fourth32 = products[0][3] & 0xffffffff; ++ uint64_t third32 = (products[0][2] & 0xffffffff) + (products[0][3] >> 32); ++ uint64_t second32 = (products[0][1] & 0xffffffff) + (products[0][2] >> 32); ++ uint64_t first32 = (products[0][0] & 0xffffffff) + (products[0][1] >> 32); ++ ++ // second row ++ third32 += products[1][3] & 0xffffffff; ++ second32 += (products[1][2] & 0xffffffff) + (products[1][3] >> 32); ++ first32 += (products[1][1] & 0xffffffff) + (products[1][2] >> 32); ++ ++ // third row ++ second32 += products[2][3] & 0xffffffff; ++ first32 += (products[2][2] & 0xffffffff) + (products[2][3] >> 32); ++ ++ // fourth row ++ first32 += products[3][3] & 0xffffffff; ++ ++ // combines the values, taking care of carry over ++ return uint128_t(first32 << 32, 0) + uint128_t(third32 >> 32, third32 << 32) + uint128_t(second32, 0) + uint128_t(fourth32); ++} ++ ++uint128_t uint128_t::operator*=(const uint128_t & rhs){ ++ *this = *this * rhs; ++ return *this; ++} ++ ++std::pair uint128_t::divmod(const uint128_t & lhs, const uint128_t & rhs) const{ ++ // Save some calculations ///////////////////// ++ if (rhs == uint128_0){ ++ throw std::runtime_error("Error: division or modulus by 0"); ++ } ++ else if (rhs == uint128_1){ ++ return std::pair (lhs, uint128_0); ++ } ++ else if (lhs == rhs){ ++ return std::pair (uint128_1, uint128_0); ++ } ++ else if ((lhs == uint128_0) || (lhs < rhs)){ ++ return std::pair (uint128_0, lhs); ++ } ++ ++ std::pair qr(uint128_0, lhs); ++ uint128_t copyd = rhs << (lhs.bits() - rhs.bits()); ++ uint128_t adder = uint128_1 << (lhs.bits() - rhs.bits()); ++ if (copyd > qr.second){ ++ copyd >>= uint128_1; ++ adder >>= uint128_1; ++ } ++ while (qr.second >= rhs){ ++ if (qr.second >= copyd){ ++ qr.second -= copyd; ++ qr.first |= adder; ++ } ++ copyd >>= uint128_1; ++ adder >>= uint128_1; ++ } ++ return qr; ++} ++ ++uint128_t uint128_t::operator/(const uint128_t & rhs) const{ ++ return divmod(*this, rhs).first; ++} ++ ++uint128_t uint128_t::operator/=(const uint128_t & rhs){ ++ *this = *this / rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator%(const uint128_t & rhs) const{ ++ return *this - (rhs * (*this / rhs)); ++} ++ ++uint128_t uint128_t::operator%=(const uint128_t & rhs){ ++ *this = *this % rhs; ++ return *this; ++} ++ ++uint128_t uint128_t::operator++(){ ++ *this += uint128_1; ++ return *this; ++} ++ ++uint128_t uint128_t::operator++(int){ ++ uint128_t temp(*this); ++ ++*this; ++ return temp; ++} ++ ++uint128_t uint128_t::operator--(){ ++ *this -= uint128_1; ++ return *this; ++} ++ ++uint128_t uint128_t::operator--(int){ ++ uint128_t temp(*this); ++ --*this; ++ return temp; ++} ++ ++uint64_t uint128_t::upper() const{ ++ return UPPER; ++} ++ ++uint64_t uint128_t::lower() const{ ++ return LOWER; ++} ++ ++uint8_t uint128_t::bits() const{ ++ uint8_t out = 0; ++ if (UPPER){ ++ out = 64; ++ uint64_t up = UPPER; ++ while (up){ ++ up >>= 1; ++ out++; ++ } ++ } ++ else{ ++ uint64_t low = LOWER; ++ while (low){ ++ low >>= 1; ++ out++; ++ } ++ } ++ return out; ++} ++ ++std::string uint128_t::str(uint8_t base, const unsigned int & len) const{ ++ if ((base < 2) || (base > 16)){ ++ throw std::invalid_argument("Base must be in th range 2-16"); ++ } ++ std::string out = ""; ++ if (!(*this)){ ++ out = "0"; ++ } ++ else{ ++ std::pair qr(*this, uint128_0); ++ do{ ++ qr = divmod(qr.first, base); ++ out = "0123456789abcdef"[(uint8_t) qr.second] + out; ++ } while (qr.first); ++ } ++ if (out.size() < len){ ++ out = std::string(len - out.size(), '0') + out; ++ } ++ return out; ++} ++ ++std::ostream & operator<<(std::ostream & stream, const uint128_t & rhs){ ++ if (stream.flags() & stream.oct){ ++ stream << rhs.str(8); ++ } ++ else if (stream.flags() & stream.dec){ ++ stream << rhs.str(10); ++ } ++ else if (stream.flags() & stream.hex){ ++ stream << rhs.str(16); ++ } ++ return stream; ++} +diff --git a/uint128_t.h b/uint128_t.h +new file mode 100644 +index 0000000..7da340a +--- /dev/null ++++ b/uint128_t.h +@@ -0,0 +1,384 @@ ++/* ++uint128_t.h ++An unsigned 128 bit integer type for C++ ++Copyright (c) 2014 Jason Lee @ calccrypto at gmail.com ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++THE SOFTWARE. ++ ++With much help from Auston Sterling ++ ++Thanks to Stefan Deigmüller for finding ++a bug in operator*. ++ ++Thanks to François Dessenne for convincing me ++to do a general rewrite of this class. ++*/ ++ ++#ifndef __UINT128_T__ ++#define __UINT128_T__ ++ ++#include ++#include ++#include ++#include ++ ++class uint128_t{ ++ private: ++ uint64_t UPPER, LOWER; ++ ++ public: ++ // Constructors ++ uint128_t(); ++ uint128_t(const uint128_t & rhs); ++ ++ template uint128_t(const T & rhs){ ++ UPPER = 0; ++ LOWER = rhs; ++ } ++ ++ template uint128_t(const S & upper_rhs, const T & lower_rhs){ ++ UPPER = upper_rhs; ++ LOWER = lower_rhs; ++ } ++ ++ // RHS input args only ++ ++ // Assignment Operator ++ uint128_t operator=(const uint128_t & rhs); ++ ++ template uint128_t operator=(const T & rhs){ ++ UPPER = 0; ++ LOWER = rhs; ++ return *this; ++ } ++ ++ // Typecast Operators ++ operator bool() const; ++ operator char() const; ++ operator int() const; ++ operator uint8_t() const; ++ operator uint16_t() const; ++ operator uint32_t() const; ++ operator uint64_t() const; ++ ++ // Bitwise Operators ++ uint128_t operator&(const uint128_t & rhs) const; ++ uint128_t operator|(const uint128_t & rhs) const; ++ uint128_t operator^(const uint128_t & rhs) const; ++ uint128_t operator&=(const uint128_t & rhs); ++ uint128_t operator|=(const uint128_t & rhs); ++ uint128_t operator^=(const uint128_t & rhs); ++ uint128_t operator~() const; ++ ++ template uint128_t operator&(const T & rhs) const{ ++ return uint128_t(0, LOWER & (uint64_t) rhs); ++ } ++ ++ template uint128_t operator|(const T & rhs) const{ ++ return uint128_t(UPPER, LOWER | (uint64_t) rhs); ++ } ++ ++ template uint128_t operator^(const T & rhs) const{ ++ return uint128_t(UPPER, LOWER ^ (uint64_t) rhs); ++ } ++ ++ template uint128_t operator&=(const T & rhs){ ++ UPPER = 0; ++ LOWER &= rhs; ++ return *this; ++ } ++ ++ template uint128_t operator|=(const T & rhs){ ++ LOWER |= (uint64_t) rhs; ++ return *this; ++ } ++ ++ template uint128_t operator^=(const T & rhs){ ++ LOWER ^= (uint64_t) rhs; ++ return *this; ++ } ++ ++ // Bit Shift Operators ++ uint128_t operator<<(const uint128_t & rhs) const; ++ uint128_t operator>>(const uint128_t & rhs) const; ++ uint128_t operator<<=(const uint128_t & rhs); ++ uint128_t operator>>=(const uint128_t & rhs); ++ ++ template uint128_t operator<<(const T & rhs) const{ ++ return *this << uint128_t(rhs); ++ } ++ ++ template uint128_t operator>>(const T & rhs) const{ ++ return *this >> uint128_t(rhs); ++ } ++ ++ template uint128_t operator<<=(const T & rhs){ ++ *this = *this << uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator>>=(const T & rhs){ ++ *this = *this >> uint128_t(rhs); ++ return *this; ++ } ++ ++ // Logical Operators ++ bool operator!() const; ++ bool operator&&(const uint128_t & rhs) const; ++ bool operator||(const uint128_t & rhs) const; ++ ++ template bool operator&&(const T & rhs){ ++ return ((bool) *this && rhs); ++ } ++ ++ template bool operator||(const T & rhs){ ++ return ((bool) *this || rhs); ++ } ++ ++ // Comparison Operators ++ bool operator==(const uint128_t & rhs) const; ++ bool operator!=(const uint128_t & rhs) const; ++ bool operator>(const uint128_t & rhs) const; ++ bool operator<(const uint128_t & rhs) const; ++ bool operator>=(const uint128_t & rhs) const; ++ bool operator<=(const uint128_t & rhs) const; ++ ++ template bool operator==(const T & rhs) const{ ++ return (!UPPER && (LOWER == (uint64_t) rhs)); ++ } ++ ++ template bool operator!=(const T & rhs) const{ ++ return (UPPER | (LOWER != (uint64_t) rhs)); ++ } ++ ++ template bool operator>(const T & rhs) const{ ++ return (UPPER || (LOWER > (uint64_t) rhs)); ++ } ++ ++ template bool operator<(const T & rhs) const{ ++ return (!UPPER)?(LOWER < (uint64_t) rhs):false; ++ } ++ ++ template bool operator>=(const T & rhs) const{ ++ return ((*this > rhs) | (*this == rhs)); ++ } ++ ++ template bool operator<=(const T & rhs) const{ ++ return ((*this < rhs) | (*this == rhs)); ++ } ++ ++ // Arithmetic Operators ++ uint128_t operator+(const uint128_t & rhs) const; ++ uint128_t operator+=(const uint128_t & rhs); ++ uint128_t operator-(const uint128_t & rhs) const; ++ uint128_t operator-=(const uint128_t & rhs); ++ uint128_t operator*(const uint128_t & rhs) const; ++ uint128_t operator*=(const uint128_t & rhs); ++ ++ private: ++ std::pair divmod(const uint128_t & lhs, const uint128_t & rhs) const; ++ ++ public: ++ uint128_t operator/(const uint128_t & rhs) const; ++ uint128_t operator/=(const uint128_t & rhs); ++ uint128_t operator%(const uint128_t & rhs) const; ++ uint128_t operator%=(const uint128_t & rhs); ++ ++ template uint128_t operator+(const T & rhs) const{ ++ return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs); ++ } ++ ++ template uint128_t operator+=(const T & rhs){ ++ UPPER = UPPER + ((LOWER + rhs) < LOWER); ++ LOWER = LOWER + rhs; ++ return *this; ++ } ++ ++ template uint128_t operator-(const T & rhs) const{ ++ return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs)); ++ } ++ ++ template uint128_t operator-=(const T & rhs){ ++ *this = *this - rhs; ++ return *this; ++ } ++ ++ template uint128_t operator*(const T & rhs) const{ ++ return (*this) * (uint128_t(rhs)); ++ } ++ ++ template uint128_t operator*=(const T & rhs){ ++ *this = *this * uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator/(const T & rhs) const{ ++ return *this / uint128_t(rhs); ++ } ++ ++ template uint128_t operator/=(const T & rhs){ ++ *this = *this / uint128_t(rhs); ++ return *this; ++ } ++ ++ template uint128_t operator%(const T & rhs) const{ ++ return *this - (rhs * (*this / rhs)); ++ } ++ ++ template uint128_t operator%=(const T & rhs){ ++ *this = *this % uint128_t(rhs); ++ return *this; ++ } ++ ++ // Increment Operator ++ uint128_t operator++(); ++ uint128_t operator++(int); ++ ++ // Decrement Operator ++ uint128_t operator--(); ++ uint128_t operator--(int); ++ ++ // Get private values ++ uint64_t upper() const; ++ uint64_t lower() const; ++ ++ // Get bitsize of value ++ uint8_t bits() const; ++ ++ // Get string representation of value ++ std::string str(uint8_t base = 10, const unsigned int & len = 0) const; ++}; ++ ++// Useful values ++extern const uint128_t uint128_0; ++extern const uint128_t uint128_1; ++extern const uint128_t uint128_64; ++extern const uint128_t uint128_128; ++ ++// lhs type T as first arguemnt ++// If the output is not a bool, casts to type T ++ ++// Bitwise Operators ++template T operator&(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs & (T) rhs.lower()); ++} ++ ++template T operator|(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs | (T) rhs.lower()); ++} ++ ++template T operator^(const T & lhs, const uint128_t & rhs){ ++ return (T) (lhs ^ (T) rhs.lower()); ++} ++ ++template T operator&=(T & lhs, const uint128_t & rhs){ ++ lhs &= (T) rhs.lower(); return lhs; ++} ++ ++template T operator|=(T & lhs, const uint128_t & rhs){ ++ lhs |= (T) rhs.lower(); return lhs; ++} ++ ++template T operator^=(T & lhs, const uint128_t & rhs){ ++ lhs ^= (T) rhs.lower(); return lhs; ++} ++ ++// Comparison Operators ++template bool operator==(const T & lhs, const uint128_t & rhs){ ++ return (!rhs.upper() && ((uint64_t) lhs == rhs.lower())); ++} ++ ++template bool operator!=(const T & lhs, const uint128_t & rhs){ ++ return (rhs.upper() | ((uint64_t) lhs != rhs.lower())); ++} ++ ++template bool operator>(const T & lhs, const uint128_t & rhs){ ++ return (!rhs.upper()) && ((uint64_t) lhs > rhs.lower()); ++} ++ ++template bool operator<(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return true; ++ } ++ return ((uint64_t) lhs < rhs.lower()); ++} ++ ++template bool operator>=(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return false; ++ } ++ return ((uint64_t) lhs >= rhs.lower()); ++} ++ ++template bool operator<=(const T & lhs, const uint128_t & rhs){ ++ if (rhs.upper()){ ++ return true; ++ } ++ return ((uint64_t) lhs <= rhs.lower()); ++} ++ ++// Arithmetic Operators ++template T operator+(const T & lhs, const uint128_t & rhs){ ++ return (T) (rhs + lhs); ++} ++ ++template T & operator+=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (rhs + lhs); ++ return lhs; ++} ++ ++template T operator-(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) - rhs); ++} ++ ++template T & operator-=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) - rhs); ++ return lhs; ++} ++ ++template T operator*(const T & lhs, const uint128_t & rhs){ ++ return lhs * (T) rhs.lower(); ++} ++ ++template T & operator*=(T & lhs, const uint128_t & rhs){ ++ lhs *= (T) rhs.lower(); ++ return lhs; ++} ++ ++template T operator/(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) / rhs); ++} ++ ++template T & operator/=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) / rhs); ++ return lhs; ++} ++ ++template T operator%(const T & lhs, const uint128_t & rhs){ ++ return (T) (uint128_t(lhs) % rhs); ++} ++ ++template T & operator%=(T & lhs, const uint128_t & rhs){ ++ lhs = (T) (uint128_t(lhs) % rhs); ++ return lhs; ++} ++ ++// IO Operator ++std::ostream & operator<<(std::ostream & stream, const uint128_t & rhs); ++#endif diff --git a/patches/ipv6.patch b/patches/ipv6.patch index 5e92174..95fb650 100644 --- a/patches/ipv6.patch +++ b/patches/ipv6.patch @@ -1,5 +1,33 @@ +diff --git a/ExtraList.cc b/ExtraList.cc +index d09f0aa..4b309fe 100644 +--- a/ExtraList.cc ++++ b/ExtraList.cc +@@ -17,6 +17,7 @@ ExtraList::ExtraList(int P1) { + for (int i = 1; i <= P; i++){ + // Create header list + struct ExtraListHeader *temp = new struct ExtraListHeader; ++ temp->field = NULL; + temp->next = NULL; + temp->prev = last; + if (i == 1) { +@@ -39,11 +40,12 @@ ExtraList::~ExtraList() { + for (int j = 0; j < N; j++){ + tempI = temp->field[j]; + // Delete list of values +- delete(tempI->value); +- delete(tempI->prob); ++ delete[] (tempI->value); ++ delete[] (tempI->prob); ++ delete(tempI); + } + first = first->next; +- delete(temp->field); ++ delete[] (temp->field); + delete(temp); + } + } diff --git a/FilterList.cc b/FilterList.cc -index c123529..fce2c09 100644 +index c123529..4677276 100644 --- a/FilterList.cc +++ b/FilterList.cc @@ -11,6 +11,9 @@ @@ -12,7 +40,44 @@ index c123529..fce2c09 100644 FilterList::FilterList() { first = last = NULL; -@@ -125,35 +128,66 @@ void FilterList::push(struct filter filt) { +@@ -20,6 +23,9 @@ FilterList::FilterList() { + FilterList::~FilterList() { + struct FilterList_item *temp; + while (first != NULL) { ++ if (first->filt.num_ext_field > 0) { ++ delete[] (first->filt.ext_field); ++ } + temp = first->next; + delete(first); + first = temp; +@@ -57,7 +63,7 @@ struct FilterList_item* FilterList::operator()(int i) { + void FilterList::insert(struct FilterList_item *item, struct filter filt) { + struct FilterList_item *newitem; + newitem = new struct FilterList_item; +- newitem->filt = filt; ++ copy_filter(newitem->filt, filt); + newitem->prev = item->prev; + newitem->next = item; + if (first == item) first = newitem; +@@ -72,7 +78,7 @@ void FilterList::insert(struct FilterList_item *item, struct filter filt) { + void FilterList::operator&=(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->prev = last; + temp->next = NULL; + if (num == 0){ +@@ -110,7 +116,7 @@ void FilterList::operator=(FilterList* L) { + void FilterList::push(struct filter filt) { + struct FilterList_item *temp; + temp = new struct FilterList_item; +- temp->filt = filt; ++ copy_filter(temp->filt, filt); + temp->next = first; + temp->prev = NULL; + if (num == 0){ +@@ -125,35 +131,66 @@ void FilterList::push(struct filter filt) { // Print the contents of the FilterList. void FilterList::print(FILE* fp) { @@ -103,11 +168,39 @@ index c123529..fce2c09 100644 // Print source port fprintf(fp, "%d : %d\t", tempfilt->filt.sp[0], tempfilt->filt.sp[1]); +diff --git a/FlagList.cc b/FlagList.cc +index 074c4e7..9a214cf 100644 +--- a/FlagList.cc ++++ b/FlagList.cc +@@ -27,8 +27,8 @@ FlagList::~FlagList() { + first[i] = temp; + } + } +- delete(first); +- delete(last); ++ delete[] (first); ++ delete[] (last); + } + + void FlagList::choose(float p, int prot, unsigned *flags, unsigned *flags_mask){ +diff --git a/PortList.cc b/PortList.cc +index 34ad3c2..4b26d15 100644 +--- a/PortList.cc ++++ b/PortList.cc +@@ -22,7 +22,7 @@ PortList::PortList(int N1) { + } + } + +-PortList::~PortList() { delete ports; } ++PortList::~PortList() { delete[] ports; } + + void PortList::read(int t, FILE *fp) { + int done = 0; diff --git a/PrefixList.cc b/PrefixList.cc -index a3df1dc..740d7ea 100644 +index a3df1dc..c3e23e5 100644 --- a/PrefixList.cc +++ b/PrefixList.cc -@@ -11,14 +11,14 @@ +@@ -11,21 +11,21 @@ #include "PrefixList.h" PrefixList::PrefixList() { @@ -124,6 +217,15 @@ index a3df1dc..740d7ea 100644 } } } + + PrefixList::~PrefixList() { +- for (int type = 0; type < 25; type++) delete prefixes[type]; +- delete prefixes; ++ for (int type = 0; type < 25; type++) delete[] prefixes[type]; ++ delete[] prefixes; + } + + void PrefixList::read(FILE* fp){ @@ -102,14 +102,14 @@ void PrefixList::read_type(int type, FILE *fp) { int tlen = 0; int slen = 0; @@ -313,6 +415,21 @@ index 2d39529..1df63a2 100644 }; class PrefixList { +diff --git a/ProtList.cc b/ProtList.cc +index a4bc451..b9bd739 100644 +--- a/ProtList.cc ++++ b/ProtList.cc +@@ -24,8 +24,8 @@ ProtList::ProtList() { + } + + ProtList::~ProtList() { +- for (int i = 0; i < 25; i++) delete protocols[i].pt_prob; +- delete protocols; ++ for (int i = 0; i < 25; i++) delete[] protocols[i].pt_prob; ++ delete[] protocols; + } + + void ProtList::read(FILE *fp) { diff --git a/README b/README index 116aac2..f104e85 100644 --- a/README @@ -346,9 +463,18 @@ index 116aac2..f104e85 100644 -flags diff --git a/TupleBST.cc b/TupleBST.cc -index 9163d9b..32e0cc8 100644 +index 9163d9b..911f1d5 100644 --- a/TupleBST.cc +++ b/TupleBST.cc +@@ -17,7 +17,7 @@ TupleBST::TupleBST() { + + TupleBST::~TupleBST() { + if (root != NULL) cleanup(root); +- delete(ListOfFilterIndexPtrs); ++ delete[] (ListOfFilterIndexPtrs); + } + + void TupleBST::cleanup(TupleBST_item* node){ @@ -34,7 +34,7 @@ void TupleBST::cleanup(TupleBST_item* node){ int TupleBST::scope(FiveTuple* ftuple){ @@ -359,7 +485,7 @@ index 9163d9b..32e0cc8 100644 } diff --git a/custom_db.cc b/custom_db.cc -index 6f8d193..0484e53 100644 +index 6f8d193..ccb8b2e 100644 --- a/custom_db.cc +++ b/custom_db.cc @@ -20,7 +20,9 @@ @@ -372,7 +498,40 @@ index 6f8d193..0484e53 100644 int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothness, float addr_scope, float port_scope, int branch){ -@@ -464,33 +466,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po +@@ -81,6 +83,9 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // Temporary filter + // struct filter temp_filter; + struct filter *temp_filters = new struct filter[num_filters+1]; ++ for (int i = 0; i < num_filters+1; i++) { ++ temp_filters[i].num_ext_field = 0; ++ } + dlist *Flist = new dlist; + struct range temp_range; + struct ppair temp_ppair; +@@ -143,6 +148,8 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + printf(" \tdone\n"); + // Free up memory + delete(protL); ++ delete(flagL); ++ delete(extraL); + delete(sparL); + delete(spemL); + delete(dparL); +@@ -219,7 +226,12 @@ int custom_db_gen(int num_filters, FilterList* filters, FILE* fp_in, int smoothn + // printf(" \tdone\n"); + + // Delete data structures +- delete(temp_filters); ++ for (int i = 0; i < num_filters+1; i++) { ++ if (temp_filters[i].num_ext_field > 0) { ++ delete[] (temp_filters[i].ext_field); ++ } ++ } ++ delete[] (temp_filters); + // printf("Done with custom_db\n"); + + return filter_cnt; +@@ -464,33 +476,64 @@ void select_ports(int port_type, struct filter *temp_filter, PortList *sparL, Po } void fprint_filter(FILE *fp, struct filter *filt){ @@ -561,7 +720,7 @@ index 3344759..afa53fb 100644 } diff --git a/dbintree.cc b/dbintree.cc -index 9274710..a2f76d1 100644 +index 9274710..9a53299 100644 --- a/dbintree.cc +++ b/dbintree.cc @@ -13,13 +13,13 @@ @@ -583,7 +742,30 @@ index 9274710..a2f76d1 100644 skew[u] = 0; corr[u] = 0; p1child[u] = 0; -@@ -99,13 +99,13 @@ void dbintree::read_skew(FILE* fp_in){ +@@ -28,10 +28,10 @@ dbintree::dbintree() { + } + + dbintree::~dbintree() { +- delete(skew); +- delete(corr); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (corr); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } +@@ -39,6 +39,7 @@ dbintree::~dbintree() { + void dbintree::delete_node(struct tnode *me){ + if (me->child0 != NULL) delete_node(me->child0); + if (me->child1 != NULL) delete_node(me->child1); ++ delete(me->stubList); + delete(me); + return; + } +@@ -99,13 +100,13 @@ void dbintree::read_skew(FILE* fp_in){ // printf("matches = %d\n",matches); // printf("level = %d, skew = %.4f\n",level,skew); if (matches == 4) { @@ -599,7 +781,7 @@ index 9274710..a2f76d1 100644 exit(1); } // printf("Read line: %d\t%.4f\t%.4f\t%.4f\n",level,p1_t,p2_t,f_skew); -@@ -147,7 +147,7 @@ void dbintree::read_corr(FILE* fp_in){ +@@ -147,7 +148,7 @@ void dbintree::read_corr(FILE* fp_in){ void dbintree::print_skew(FILE *fp) { fprintf(fp,"Level\tp1\tp2\tSkew\n"); @@ -608,7 +790,7 @@ index 9274710..a2f76d1 100644 fprintf(fp,"%d\t%.4f\t%.4f\t%.4f\n", i,p1child[i],p2child[i],skew[i]); } -@@ -157,14 +157,14 @@ void dbintree::print_skew(FILE *fp) { +@@ -157,14 +158,14 @@ void dbintree::print_skew(FILE *fp) { void dbintree::print_corr(FILE *fp) { fprintf(fp,"Level\tCorr\n"); @@ -625,7 +807,7 @@ index 9274710..a2f76d1 100644 // Create copy of list dlist *temp_list = new dlist(); (*temp_list)=(Flist); -@@ -221,7 +221,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ +@@ -221,7 +222,7 @@ void dbintree::add2child_stublist(struct tnode *node, int dir, int filt){ return; } @@ -634,7 +816,7 @@ index 9274710..a2f76d1 100644 int Flist_size = 0; int lev = node->lvl; -@@ -237,21 +237,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -237,21 +238,21 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // printf("Flist_size = %d\n",Flist_size); double temp; @@ -663,7 +845,7 @@ index 9274710..a2f76d1 100644 } // Allocate temp_list's -@@ -297,7 +297,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -297,7 +298,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // printf("Flist_size = %d, tempList: ",Flist_size); tempList->print(stdout); printf("\n"); // if lev1_flag == 1, dump all lev1 filters to one side // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); @@ -672,7 +854,7 @@ index 9274710..a2f76d1 100644 // printf("add_stub: Enforcing nesting limit\n"); // Add all filters to stublist and let the finish_node process distribute them int fptr; -@@ -331,7 +331,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -331,7 +332,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str // sa_len > lvl // Prevent prefix nesting sa = sa << lev; @@ -681,7 +863,7 @@ index 9274710..a2f76d1 100644 // sa now equals next "bit" of source address if (filters[fptr].sa_len == (lev+1)) { // Source prefix will be exhausted at next level -@@ -407,7 +407,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str +@@ -407,7 +408,7 @@ void dbintree::add_stub(struct tnode *node, unsigned int addr, dlist* Flist, str return; } @@ -690,7 +872,7 @@ index 9274710..a2f76d1 100644 int Flist_size = 0; int stubList_size = 0; int lev = node->lvl; -@@ -479,20 +479,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, +@@ -479,20 +480,20 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, double temp; int path; @@ -717,7 +899,7 @@ index 9274710..a2f76d1 100644 } // Create an empty list -@@ -519,7 +519,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, +@@ -519,7 +520,7 @@ void dbintree::finish_node(struct tnode *node, unsigned int addr, dlist* Flist, // If at the nesting threshold and list has more than one child, // then split list (allocate all nodes with level == lev1 to one path) // printf("lev = %d, MyNest = %d, Nest = %d, lev1_flag = %d\n",lev,MyNest,Nest,lev1_flag); @@ -5271,7 +5453,7 @@ index 0000000..2f10279 diff --git a/makefile b/makefile old mode 100755 new mode 100644 -index 773f4c1..2c86037 +index 773f4c1..ca7b1d8 --- a/makefile +++ b/makefile @@ -9,8 +9,9 @@ @@ -5281,7 +5463,7 @@ index 773f4c1..2c86037 +LIB = -I./ip-address/include ##CFLAGS = -g -pg -CFLAGS = -O2 -+CFLAGS = -O2 -g -std=c++11 $(LIB) ++CFLAGS = -O2 -std=c++11 $(LIB) .cc.o: ${CC} ${CFLAGS} -c $*.cc @@ -5438,7 +5620,7 @@ index 38771e7..fbac9d3 100644 // Check source address match diff --git a/sbintree.cc b/sbintree.cc -index d755099..6a83b51 100644 +index d755099..062fbaf 100644 --- a/sbintree.cc +++ b/sbintree.cc @@ -13,12 +13,12 @@ @@ -5458,6 +5640,19 @@ index d755099..6a83b51 100644 skew[u] = 0; p1child[u] = 0; p2child[u] = 0; +@@ -26,9 +26,9 @@ sbintree::sbintree() { + } + + sbintree::~sbintree() { +- delete(skew); +- delete(p1child); +- delete(p2child); ++ delete[] (skew); ++ delete[] (p1child); ++ delete[] (p2child); + // call recursive node destructor + if (root != NULL) delete_node(root); + } @@ -96,13 +96,13 @@ void sbintree::read_skew(FILE* fp_in){ // printf("matches = %d\n",matches); // printf("level = %d, skew = %.4f\n",level,skew); @@ -5536,6 +5731,17 @@ index d755099..6a83b51 100644 // Allocate nest_list dlist *nest_list = new dlist(); dlist *other_list = new dlist(); +@@ -291,6 +291,10 @@ void sbintree::add_node(struct stnode *prnt, int lev, int dir, unsigned int addr + add_node(me, lev1, 1, addr1, other_list, filters, MyNest); + } + } ++ ++ // Deallocate nest_list ++ delete(nest_list); ++ delete(other_list); + } + else { + // Othewise, branch based on branching probability and skew diff --git a/sbintree.h b/sbintree.h index b085696..937d941 100644 --- a/sbintree.h @@ -5550,7 +5756,7 @@ index b085696..937d941 100644 public: sbintree(); diff --git a/stdinc.h b/stdinc.h -index f566e0f..f731846 100644 +index f566e0f..3c2f685 100644 --- a/stdinc.h +++ b/stdinc.h @@ -10,6 +10,7 @@ @@ -5589,6 +5795,37 @@ index f566e0f..f731846 100644 int sa_len; // IP source address mask length int da_len; // IP destination address mask length int sp[2]; // Transport source port range [low,high] +@@ -69,6 +70,30 @@ struct filter { + int *ext_field; // Pointer to array of extra header fields + }; + ++// Do a deep copy of orig filter ++inline void copy_filter(struct filter& copy, struct filter orig) { ++ copy.sa = orig.sa; ++ copy.da = orig.da; ++ copy.sa_len = orig.sa_len; ++ copy.da_len = orig.da_len; ++ copy.sp[0] = orig.sp[0]; ++ copy.sp[1] = orig.sp[1]; ++ copy.dp[0] = orig.dp[0]; ++ copy.dp[1] = orig.dp[1]; ++ copy.prot_num = orig.prot_num; ++ copy.flags = orig.flags; ++ copy.flags_mask = orig.flags_mask; ++ copy.num_ext_field = orig.num_ext_field; ++ if (copy.num_ext_field > 0) { ++ copy.ext_field = new int[copy.num_ext_field]; ++ for (int i = 0; i < copy.num_ext_field; i++) { ++ copy.ext_field[i] = orig.ext_field[i]; ++ } ++ } else { ++ copy.ext_field = NULL; ++ } ++} ++ + struct range { + int low; + int high; diff --git a/uint128_t.cc b/uint128_t.cc new file mode 100644 index 0000000..1e16bbd diff --git a/seeds/of1_seed b/seeds/of1_seed new file mode 100644 index 0000000..d8de126 --- /dev/null +++ b/seeds/of1_seed @@ -0,0 +1,476 @@ +-scale +13778 +# +-prots +0 0.3103498330672086 0.9679607109448082 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.032039289055191766 +17 0.2551894324285092 0.6968145620022753 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3031854379977247 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +6 0.25243141239657424 0.7044278320874066 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.29557216791259344 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1 0.18202932210770795 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +# +-flags +0 0x0000/0x0000,1.00000000 +17 0x0000/0x0000,1.00000000 +6 0x0000/0x0000,1.00000000 +1 0x0000/0x0000,1.00000000 +# +-extra +0 +# +-spar +# +-spem +0.9197080291970803 67:67 +0.0364963503649635 2888:2888 +0.0072992700729927005 443:443 +0.0364963503649635 22:22 +# +-dpar +# +-dpem +0.05199462124607799 8192:8192 +0.05199462124607799 1:1 +0.05199462124607799 2048:2048 +0.005378753922008068 61440:61440 +0.005378753922008068 57344:57344 +0.05199462124607799 4096:4096 +0.05199462124607799 256:256 +0.005378753922008068 65024:65024 +0.05199462124607799 4:4 +0.05199462124607799 64:64 +0.005378753922008068 65408:65408 +0.05199462124607799 8:8 +0.005378753922008068 65520:65520 +0.05199462124607799 16384:16384 +0.03182429403854774 67:67 +0.005378753922008068 65532:65532 +0.05199462124607799 2:2 +0.05199462124607799 32768:32768 +0.05199462124607799 16:16 +0.05199462124607799 1024:1024 +0.005378753922008068 63488:63488 +0.04885701479157328 68:68 +0.05199462124607799 32:32 +0.005378753922008068 65528:65528 +0.005378753922008068 65472:65472 +0.005378753922008068 49152:49152 +0.05199462124607799 128:128 +0.005378753922008068 65280:65280 +0.05199462124607799 512:512 +0.005378753922008068 64512:64512 +0.005378753922008068 65504:65504 +0.0017929179740026895 443:443 +0.0017929179740026895 8443:8443 +0.005378753922008068 65534:65534 +0.0017929179740026895 22:22 +0.0017929179740026895 3389:3389 +0.00044822949350067237 45518:45518 +0.00044822949350067237 45530:45530 +0.00044822949350067237 40502:40502 +0.00044822949350067237 45527:45527 +0.00044822949350067237 45521:45521 +0.00044822949350067237 35008:35008 +0.00044822949350067237 45524:45524 +0.00044822949350067237 38356:38356 +0.00044822949350067237 57929:57929 +0.00044822949350067237 38352:38352 +0.00044822949350067237 38365:38365 +# +-wc_wc +64,0.9994803845154585 32,1.0 +40,8.660258075690655e-05 32,1.0 +56,8.660258075690655e-05 24,1.0 +55,8.660258075690655e-05 23,1.0 +62,8.660258075690655e-05 30,1.0 +36,8.660258075690655e-05 4,1.0 +52,8.660258075690655e-05 20,1.0 +# +-wc_hi +# +-hi_wc +# +-hi_hi +# +-wc_lo +# +-lo_wc +# +-hi_lo +# +-lo_hi +# +-lo_lo +# +-wc_ar +# +-ar_wc +# +-hi_ar +# +-ar_hi +# +-wc_em +64,1.0 32,1.0 +# +-em_wc +# +-hi_em +# +-em_hi +# +-lo_ar +# +-ar_lo +# +-lo_em +# +-em_lo +# +-ar_ar +# +-ar_em +# +-em_ar +# +-em_em +64,1.0 32,1.0 +# +-snest +1 +# +-sskew +0 0.0 1.0 0.9545500251382605 +1 0.0 1.0 0.5359929339025468 +2 0.0 1.0 0.9880907752041772 +3 0.75 0.25 0.9747003994673769 +4 0.8 0.2 0.6956144159791576 +5 0.8333333333333334 0.16666666666666666 0.9832229580573951 +6 0.7142857142857143 0.2857142857142857 0.6842970166652276 +7 0.7777777777777778 0.2222222222222222 0.7461365099806825 +8 0.9 0.1 0.9967700258397932 +9 0.8181818181818182 0.18181818181818182 0.9690445516809689 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 0.9230769230769231 0.07692307692307693 0.7176470588235294 +13 0.8571428571428571 0.14285714285714285 0.6678082191780822 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.9375 0.0625 0.9976069398743643 +17 1.0 0.0 0.0 +18 0.8235294117647058 0.17647058823529413 0.49452782989368355 +19 0.85 0.15 0.49063710872296934 +20 0.9565217391304348 0.043478260869565216 0.7818181818181819 +21 0.7916666666666666 0.20833333333333334 0.748101963356065 +22 0.7586206896551724 0.2413793103448276 0.6276331456287173 +23 0.6111111111111112 0.3888888888888889 0.49384178996279193 +24 0.62 0.38 0.3075823236773248 +25 0.5757575757575758 0.42424242424242425 0.23646709280295494 +26 0.5425531914893617 0.4574468085106383 0.18149615429139418 +27 0.49635036496350365 0.5036496350364964 0.13074395855860385 +28 0.2807017543859649 0.7192982456140351 0.38317258552895755 +29 0.35051546391752575 0.6494845360824743 0.3448024522585926 +30 0.49375 0.50625 0.22833426861204636 +31 0.6569037656903766 0.34309623430962344 0.04181184668989549 +32 0.0 0.0 0.0 +# +-dnest +2 +# +-dskew +0 0.0 1.0 0.027447698744769822 +1 0.0 1.0 0.26004659289458354 +2 0.5 0.5 0.9992122883024813 +3 0.3333333333333333 0.6666666666666666 0.48807394156231365 +4 0.75 0.25 0.950891460744448 +5 0.6 0.4 0.9697815500620608 +6 0.8571428571428571 0.14285714285714285 0.9450511945392491 +7 0.875 0.125 0.10588235294117643 +8 0.8888888888888888 0.1111111111111111 0.9375 +9 0.8 0.2 0.9489707434776052 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 0.9166666666666666 0.08333333333333333 0.012987012987012991 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.9230769230769231 0.07692307692307693 0.7102803738317758 +17 0.8571428571428571 0.14285714285714285 0.43175287356321834 +18 0.625 0.375 0.4813902218940979 +19 0.6818181818181818 0.3181818181818182 0.47424064275916133 +20 0.6071428571428571 0.39285714285714285 0.4404761904761905 +21 0.7692307692307693 0.23076923076923078 0.5677248677248677 +22 0.8958333333333334 0.10416666666666667 0.6551219512195121 +23 0.7924528301886793 0.20754716981132076 0.4103077091547137 +24 0.8125 0.1875 0.38967230944842884 +25 0.8947368421052632 0.10526315789473684 0.2707473635946813 +26 0.8809523809523809 0.11904761904761904 0.2 +27 0.9148936170212766 0.0851063829787234 0.23967470760233917 +28 1.0 0.0 0.0 +29 1.0 0.0 0.0 +30 0.9285714285714286 0.07142857142857142 0.5 +31 1.0 0.0 0.0 +32 0.0 0.0 0.0 +# +-pcorr +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +# +-openflow +--- +in_port: + '71': 2 + '50': 2 + '393': 2 + '471': 2 + '249': 2 + '308': 2 + '180': 2 + '522': 2 + '81': 2 + '69': 2 + '70': 2 + '360': 2 + '1': 2 + '269': 2 + '173': 2 + '470': 2 + '310': 2 + '289': 2 + '521': 2 + '37554': 1 + '37618': 1 + '37742': 1 + '37653': 1 + '37553': 1 + '37677': 1 + '37612': 1 + '37702': 1 + '37715': 1 + '37607': 1 + '37660': 1 + '37598': 1 + '37670': 1 + '37703': 1 + '37640': 1 + '37672': 1 + '37696': 1 + '37597': 1 + '36736': 1 + '37737': 1 + '37621': 1 + '37225': 1 + '37690': 1 + '37562': 1 + '37680': 1 + '37617': 1 + '36697': 1 + '37555': 1 + '37716': 1 + '37611': 1 + '37561': 1 + '37581': 1 + '37663': 1 + '37714': 1 + '36666': 1 + '36464': 1 + '37606': 1 + '37681': 1 + '37605': 1 + '37748': 1 + '37616': 1 + '36662': 1 + '37725': 1 + '37664': 1 + '37700': 1 + '36717': 1 + '37548': 1 + '37719': 1 + '36803': 1 + '37710': 1 + '37673': 1 + '37676': 1 + '37587': 1 + '37651': 1 + '37659': 1 + '37685': 1 + '37602': 1 + '37579': 1 + '37600': 1 + '37620': 1 + '37614': 1 + '37695': 1 + '37648': 1 + '37549': 1 + '37736': 1 + '37705': 1 + '37678': 1 + '37662': 1 + '37622': 1 + '37665': 1 + '37642': 1 + '37720': 1 + '37722': 1 + '37655': 1 + '36646': 1 + '37713': 1 + '37744': 1 + '37647': 1 + '37686': 1 + '37727': 1 + '37563': 1 + '37738': 1 + '37080': 1 + '37550': 1 + '37552': 1 + '37675': 1 + '37583': 1 + '36361': 1 + '37551': 1 + '37646': 1 + '37656': 1 + '36658': 1 + '37545': 1 + '37601': 1 + '37643': 1 + '37657': 1 + '37560': 1 + '37084': 1 + '37741': 1 + '37743': 1 + '37585': 1 + '37556': 1 + '37683': 1 + '37688': 1 +eth_type: + '0x800': 9502 +dl_src: + fa:16:3e: 838 +dl_dst: + 01:80:c2: 1 + 01:00:0c: 4 + 00:e0:2b: 3 + fa:16:3e: 12534 + ff:ff:ff: 6 + '01:00:00': 85 + c2:81:09: 15 + '00:00:00': 2 +unique_vlan_ids_count: 0 +empty_rules_count: 3190 +rule_distribution: +- attributes: + - dl_dst + count: 1016 +- attributes: + - in_port + count: 142 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + - tp_dst + count: 384 +- attributes: + - dl_dst + - nw_dst + count: 180 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - tp_dst + count: 1710 +- attributes: + - nw_src + count: 3 +- attributes: + - nw_dst + - tp_dst + - tp_src + count: 71 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - nw_src + count: 7224 +- attributes: + - nw_dst + count: 81 +- attributes: + - dl_dst + - nw_dst + - tp_dst + - tp_src + count: 54 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + count: 46 +- attributes: + - dl_dst + - nw_dst + - nw_src + count: 2408 +- attributes: + - dl_src + count: 81 +- attributes: + - dl_src + - nw_src + count: 228 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + count: 138 +- attributes: + - dl_dst + - dl_src + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 7 +- attributes: + - dl_dst + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 5 +# diff --git a/seeds/of2_seed b/seeds/of2_seed new file mode 100644 index 0000000..ddb2b90 --- /dev/null +++ b/seeds/of2_seed @@ -0,0 +1,8656 @@ +-scale +16431 +# +-prots +0 0.7094516462783762 0.2838637728403534 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7161362271596465 +17 0.09822895745846266 0.8736059479553904 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.12639405204460966 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +6 0.10553222567098777 0.8131487889273357 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.18685121107266436 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +1 0.08678717059217333 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +# +-flags +0 0x0000/0x0000,1.00000000 +17 0x0000/0x0000,1.00000000 +6 0x0000/0x0000,1.00000000 +1 0x0000/0x0000,1.00000000 +# +-extra +0 +# +-spar +# +-spem +0.018806899856252994 67:67 +0.9808337326305702 445:445 +0.00023957834211787255 443:443 +0.00011978917105893628 2049:2049 +# +-dpar +# +-dpem +0.0027039206849932404 2048:2048 +0.0009013068949977468 61440:61440 +0.0027039206849932404 4096:4096 +0.001013970256872465 57344:57344 +0.0027039206849932404 256:256 +0.0009013068949977468 65024:65024 +0.0027039206849932404 64:64 +0.0009013068949977468 65408:65408 +0.0027039206849932404 8:8 +0.0009013068949977468 65520:65520 +0.015434880576836413 67:67 +0.0027039206849932404 2:2 +0.0009013068949977468 65532:65532 +0.004506534474988734 68:68 +0.0027039206849932404 1024:1024 +0.0009013068949977468 63488:63488 +0.0027039206849932404 4:4 +0.0009013068949977468 65528:65528 +0.0027039206849932404 32:32 +0.0009013068949977468 65472:65472 +0.0009013068949977468 49152:49152 +0.0027039206849932404 8192:8192 +0.0027039206849932404 128:128 +0.0009013068949977468 65280:65280 +0.0028165840468679587 32768:32768 +0.0027039206849932404 16384:16384 +0.0027039206849932404 16:16 +0.0009013068949977468 65504:65504 +0.0027039206849932404 512:512 +0.0009013068949977468 64512:64512 +0.0009013068949977468 65534:65534 +0.0027039206849932404 1:1 +0.0004506534474988734 22:22 +0.0004506534474988734 3389:3389 +0.0004506534474988734 443:443 +0.00011266336187471834 34719:34719 +0.00011266336187471834 57768:57768 +0.00011266336187471834 56047:56047 +0.00011266336187471834 60616:60616 +0.00011266336187471834 59836:59836 +0.00011266336187471834 56178:56178 +0.00011266336187471834 57143:57143 +0.00011266336187471834 34044:34044 +0.00011266336187471834 34905:34905 +0.00011266336187471834 59412:59412 +0.00011266336187471834 57743:57743 +0.00011266336187471834 59535:59535 +0.00011266336187471834 58303:58303 +0.00011266336187471834 56816:56816 +0.00011266336187471834 60760:60760 +0.00011266336187471834 60146:60146 +0.00011266336187471834 55614:55614 +0.00011266336187471834 34966:34966 +0.00011266336187471834 58060:58060 +0.00011266336187471834 32949:32949 +0.00011266336187471834 58394:58394 +0.00011266336187471834 56050:56050 +0.00011266336187471834 59598:59598 +0.00011266336187471834 59095:59095 +0.00011266336187471834 60219:60219 +0.00011266336187471834 59381:59381 +0.00011266336187471834 35540:35540 +0.00011266336187471834 34703:34703 +0.00011266336187471834 60722:60722 +0.00011266336187471834 35511:35511 +0.00011266336187471834 55996:55996 +0.00011266336187471834 55988:55988 +0.00011266336187471834 34426:34426 +0.00011266336187471834 60416:60416 +0.00011266336187471834 58102:58102 +0.00011266336187471834 33534:33534 +0.00011266336187471834 60693:60693 +0.00011266336187471834 56608:56608 +0.00011266336187471834 35545:35545 +0.00011266336187471834 34652:34652 +0.00011266336187471834 34488:34488 +0.00011266336187471834 60561:60561 +0.00011266336187471834 56479:56479 +0.00011266336187471834 59651:59651 +0.00011266336187471834 58208:58208 +0.00011266336187471834 60364:60364 +0.00011266336187471834 56424:56424 +0.00011266336187471834 59544:59544 +0.00011266336187471834 34438:34438 +0.00011266336187471834 33821:33821 +0.00011266336187471834 35393:35393 +0.00011266336187471834 60848:60848 +0.00011266336187471834 59063:59063 +0.00011266336187471834 57746:57746 +0.00011266336187471834 57899:57899 +0.00011266336187471834 57808:57808 +0.00011266336187471834 58412:58412 +0.00011266336187471834 58219:58219 +0.00011266336187471834 56996:56996 +0.00011266336187471834 57264:57264 +0.00011266336187471834 55949:55949 +0.00011266336187471834 60111:60111 +0.00011266336187471834 59508:59508 +0.00011266336187471834 33574:33574 +0.00011266336187471834 59245:59245 +0.00011266336187471834 58678:58678 +0.00011266336187471834 33361:33361 +0.00011266336187471834 59620:59620 +0.00011266336187471834 59390:59390 +0.00011266336187471834 58672:58672 +0.00011266336187471834 34066:34066 +0.00011266336187471834 56589:56589 +0.00011266336187471834 60012:60012 +0.00011266336187471834 56187:56187 +0.00011266336187471834 35483:35483 +0.00011266336187471834 34722:34722 +0.00011266336187471834 60574:60574 +0.00011266336187471834 57804:57804 +0.00011266336187471834 33948:33948 +0.00011266336187471834 59299:59299 +0.00011266336187471834 58986:58986 +0.00011266336187471834 34218:34218 +0.00011266336187471834 59821:59821 +0.00011266336187471834 56543:56543 +0.00011266336187471834 35475:35475 +0.00011266336187471834 60432:60432 +0.00011266336187471834 55842:55842 +0.00011266336187471834 57088:57088 +0.00011266336187471834 57197:57197 +0.00011266336187471834 58199:58199 +0.00011266336187471834 59639:59639 +0.00011266336187471834 60461:60461 +0.00011266336187471834 57549:57549 +0.00011266336187471834 59487:59487 +0.00011266336187471834 58932:58932 +0.00011266336187471834 35136:35136 +0.00011266336187471834 59715:59715 +0.00011266336187471834 58780:58780 +0.00011266336187471834 57479:57479 +0.00011266336187471834 56519:56519 +0.00011266336187471834 32873:32873 +0.00011266336187471834 59571:59571 +0.00011266336187471834 57456:57456 +0.00011266336187471834 58256:58256 +0.00011266336187471834 58229:58229 +0.00011266336187471834 56625:56625 +0.00011266336187471834 56219:56219 +0.00011266336187471834 57307:57307 +0.00011266336187471834 33091:33091 +0.00011266336187471834 57691:57691 +0.00011266336187471834 60293:60293 +0.00011266336187471834 57393:57393 +0.00011266336187471834 58776:58776 +0.00011266336187471834 60571:60571 +0.00011266336187471834 59371:59371 +0.00011266336187471834 58824:58824 +0.00011266336187471834 57123:57123 +0.00011266336187471834 56488:56488 +0.00011266336187471834 57488:57488 +0.00011266336187471834 34832:34832 +0.00011266336187471834 60216:60216 +0.00011266336187471834 59691:59691 +0.00011266336187471834 33462:33462 +0.00011266336187471834 35527:35527 +0.00011266336187471834 34540:34540 +0.00011266336187471834 57257:57257 +0.00011266336187471834 59298:59298 +0.00011266336187471834 34819:34819 +0.00011266336187471834 32998:32998 +0.00011266336187471834 60818:60818 +0.00011266336187471834 56036:56036 +0.00011266336187471834 34512:34512 +0.00011266336187471834 59649:59649 +0.00011266336187471834 57477:57477 +0.00011266336187471834 59248:59248 +0.00011266336187471834 58983:58983 +0.00011266336187471834 57201:57201 +0.00011266336187471834 58547:58547 +0.00011266336187471834 56711:56711 +0.00011266336187471834 59943:59943 +0.00011266336187471834 58684:58684 +0.00011266336187471834 57498:57498 +0.00011266336187471834 34229:34229 +0.00011266336187471834 33393:33393 +0.00011266336187471834 59779:59779 +0.00011266336187471834 35261:35261 +0.00011266336187471834 34150:34150 +0.00011266336187471834 57306:57306 +0.00011266336187471834 34814:34814 +0.00011266336187471834 58977:58977 +0.00011266336187471834 59358:59358 +0.00011266336187471834 57721:57721 +0.00011266336187471834 34038:34038 +0.00011266336187471834 60540:60540 +0.00011266336187471834 57979:57979 +0.00011266336187471834 34823:34823 +0.00011266336187471834 33674:33674 +0.00011266336187471834 60700:60700 +0.00011266336187471834 35544:35544 +0.00011266336187471834 60763:60763 +0.00011266336187471834 35403:35403 +0.00011266336187471834 34348:34348 +0.00011266336187471834 58430:58430 +0.00011266336187471834 35197:35197 +0.00011266336187471834 33902:33902 +0.00011266336187471834 59501:59501 +0.00011266336187471834 58844:58844 +0.00011266336187471834 34983:34983 +0.00011266336187471834 56145:56145 +0.00011266336187471834 58453:58453 +0.00011266336187471834 55864:55864 +0.00011266336187471834 33872:33872 +0.00011266336187471834 32952:32952 +0.00011266336187471834 56832:56832 +0.00011266336187471834 34143:34143 +0.00011266336187471834 34692:34692 +0.00011266336187471834 56129:56129 +0.00011266336187471834 60836:60836 +0.00011266336187471834 35331:35331 +0.00011266336187471834 34331:34331 +0.00011266336187471834 33933:33933 +0.00011266336187471834 60253:60253 +0.00011266336187471834 32801:32801 +0.00011266336187471834 59795:59795 +0.00011266336187471834 59230:59230 +0.00011266336187471834 33995:33995 +0.00011266336187471834 32874:32874 +0.00011266336187471834 34403:34403 +0.00011266336187471834 35518:35518 +0.00011266336187471834 34377:34377 +0.00011266336187471834 34801:34801 +0.00011266336187471834 34474:34474 +0.00011266336187471834 33235:33235 +0.00011266336187471834 33374:33374 +0.00011266336187471834 59050:59050 +0.00011266336187471834 59950:59950 +0.00011266336187471834 59570:59570 +0.00011266336187471834 33183:33183 +0.00011266336187471834 57998:57998 +0.00011266336187471834 58313:58313 +0.00011266336187471834 58591:58591 +0.00011266336187471834 59197:59197 +0.00011266336187471834 58690:58690 +0.00011266336187471834 58957:58957 +0.00011266336187471834 56854:56854 +0.00011266336187471834 55845:55845 +0.00011266336187471834 33285:33285 +0.00011266336187471834 56373:56373 +0.00011266336187471834 55926:55926 +0.00011266336187471834 58622:58622 +0.00011266336187471834 56101:56101 +0.00011266336187471834 60572:60572 +0.00011266336187471834 60747:60747 +0.00011266336187471834 33335:33335 +0.00011266336187471834 60728:60728 +0.00011266336187471834 60529:60529 +0.00011266336187471834 60876:60876 +0.00011266336187471834 59375:59375 +0.00011266336187471834 59219:59219 +0.00011266336187471834 57969:57969 +0.00011266336187471834 57135:57135 +0.00011266336187471834 35400:35400 +0.00011266336187471834 56286:56286 +0.00011266336187471834 58791:58791 +0.00011266336187471834 56126:56126 +0.00011266336187471834 59739:59739 +0.00011266336187471834 57976:57976 +0.00011266336187471834 57776:57776 +0.00011266336187471834 57491:57491 +0.00011266336187471834 57335:57335 +0.00011266336187471834 57063:57063 +0.00011266336187471834 58799:58799 +0.00011266336187471834 57892:57892 +0.00011266336187471834 60373:60373 +0.00011266336187471834 59400:59400 +0.00011266336187471834 34633:34633 +0.00011266336187471834 56410:56410 +0.00011266336187471834 60893:60893 +0.00011266336187471834 60892:60892 +0.00011266336187471834 58871:58871 +0.00011266336187471834 57162:57162 +0.00011266336187471834 55730:55730 +0.00011266336187471834 56731:56731 +0.00011266336187471834 58378:58378 +0.00011266336187471834 60525:60525 +0.00011266336187471834 33140:33140 +0.00011266336187471834 60107:60107 +0.00011266336187471834 58090:58090 +0.00011266336187471834 59761:59761 +0.00011266336187471834 58012:58012 +0.00011266336187471834 33360:33360 +0.00011266336187471834 59869:59869 +0.00011266336187471834 35315:35315 +0.00011266336187471834 33839:33839 +0.00011266336187471834 59297:59297 +0.00011266336187471834 59346:59346 +0.00011266336187471834 57247:57247 +0.00011266336187471834 56936:56936 +0.00011266336187471834 57696:57696 +0.00011266336187471834 33409:33409 +0.00011266336187471834 57843:57843 +0.00011266336187471834 33254:33254 +0.00011266336187471834 59316:59316 +0.00011266336187471834 59527:59527 +0.00011266336187471834 33738:33738 +0.00011266336187471834 60627:60627 +0.00011266336187471834 56830:56830 +0.00011266336187471834 60341:60341 +0.00011266336187471834 59513:59513 +0.00011266336187471834 60721:60721 +0.00011266336187471834 58068:58068 +0.00011266336187471834 59432:59432 +0.00011266336187471834 56461:56461 +0.00011266336187471834 34081:34081 +0.00011266336187471834 34728:34728 +0.00011266336187471834 56184:56184 +0.00011266336187471834 56025:56025 +0.00011266336187471834 58450:58450 +0.00011266336187471834 59733:59733 +0.00011266336187471834 58619:58619 +0.00011266336187471834 58460:58460 +0.00011266336187471834 58375:58375 +0.00011266336187471834 34827:34827 +0.00011266336187471834 34361:34361 +0.00011266336187471834 60559:60559 +0.00011266336187471834 34481:34481 +0.00011266336187471834 35444:35444 +0.00011266336187471834 35039:35039 +0.00011266336187471834 33917:33917 +0.00011266336187471834 59704:59704 +0.00011266336187471834 33045:33045 +0.00011266336187471834 59027:59027 +0.00011266336187471834 59262:59262 +0.00011266336187471834 56518:56518 +0.00011266336187471834 55818:55818 +0.00011266336187471834 59312:59312 +0.00011266336187471834 56459:56459 +0.00011266336187471834 60021:60021 +0.00011266336187471834 59040:59040 +0.00011266336187471834 60883:60883 +0.00011266336187471834 33082:33082 +0.00011266336187471834 58101:58101 +0.00011266336187471834 60326:60326 +0.00011266336187471834 34675:34675 +0.00011266336187471834 58427:58427 +0.00011266336187471834 56655:56655 +0.00011266336187471834 32805:32805 +0.00011266336187471834 59142:59142 +0.00011266336187471834 60882:60882 +0.00011266336187471834 35143:35143 +0.00011266336187471834 56231:56231 +0.00011266336187471834 59842:59842 +0.00011266336187471834 55887:55887 +0.00011266336187471834 33545:33545 +0.00011266336187471834 58893:58893 +0.00011266336187471834 35070:35070 +0.00011266336187471834 34191:34191 +0.00011266336187471834 59984:59984 +0.00011266336187471834 32941:32941 +0.00011266336187471834 59743:59743 +0.00011266336187471834 58925:58925 +0.00011266336187471834 57927:57927 +0.00011266336187471834 56335:56335 +0.00011266336187471834 34873:34873 +0.00011266336187471834 57369:57369 +0.00011266336187471834 59622:59622 +0.00011266336187471834 34943:34943 +0.00011266336187471834 34815:34815 +0.00011266336187471834 59642:59642 +0.00011266336187471834 34242:34242 +0.00011266336187471834 58436:58436 +0.00011266336187471834 34574:34574 +0.00011266336187471834 34119:34119 +0.00011266336187471834 58627:58627 +0.00011266336187471834 34203:34203 +0.00011266336187471834 35537:35537 +0.00011266336187471834 58869:58869 +0.00011266336187471834 57763:57763 +0.00011266336187471834 32774:32774 +0.00011266336187471834 34718:34718 +0.00011266336187471834 34269:34269 +0.00011266336187471834 60260:60260 +0.00011266336187471834 58018:58018 +0.00011266336187471834 34569:34569 +0.00011266336187471834 32778:32778 +0.00011266336187471834 34160:34160 +0.00011266336187471834 33758:33758 +0.00011266336187471834 33294:33294 +0.00011266336187471834 57327:57327 +0.00011266336187471834 56530:56530 +0.00011266336187471834 56108:56108 +0.00011266336187471834 60581:60581 +0.00011266336187471834 58958:58958 +0.00011266336187471834 33608:33608 +0.00011266336187471834 60038:60038 +0.00011266336187471834 34857:34857 +0.00011266336187471834 35076:35076 +0.00011266336187471834 33730:33730 +0.00011266336187471834 59861:59861 +0.00011266336187471834 57187:57187 +0.00011266336187471834 56960:56960 +0.00011266336187471834 56247:56247 +0.00011266336187471834 55929:55929 +0.00011266336187471834 60612:60612 +0.00011266336187471834 58006:58006 +0.00011266336187471834 34146:34146 +0.00011266336187471834 60834:60834 +0.00011266336187471834 57925:57925 +0.00011266336187471834 55783:55783 +0.00011266336187471834 60988:60988 +0.00011266336187471834 58848:58848 +0.00011266336187471834 56871:56871 +0.00011266336187471834 32974:32974 +0.00011266336187471834 58870:58870 +0.00011266336187471834 57263:57263 +0.00011266336187471834 60377:60377 +0.00011266336187471834 58268:58268 +0.00011266336187471834 35460:35460 +0.00011266336187471834 57415:57415 +0.00011266336187471834 56507:56507 +0.00011266336187471834 59752:59752 +0.00011266336187471834 56462:56462 +0.00011266336187471834 56602:56602 +0.00011266336187471834 60521:60521 +0.00011266336187471834 33983:33983 +0.00011266336187471834 59353:59353 +0.00011266336187471834 59190:59190 +0.00011266336187471834 55968:55968 +0.00011266336187471834 60869:60869 +0.00011266336187471834 34942:34942 +0.00011266336187471834 34856:34856 +0.00011266336187471834 32905:32905 +0.00011266336187471834 33507:33507 +0.00011266336187471834 58094:58094 +0.00011266336187471834 56333:56333 +0.00011266336187471834 55649:55649 +0.00011266336187471834 35268:35268 +0.00011266336187471834 59185:59185 +0.00011266336187471834 60925:60925 +0.00011266336187471834 60526:60526 +0.00011266336187471834 58522:58522 +0.00011266336187471834 59264:59264 +0.00011266336187471834 34937:34937 +0.00011266336187471834 33489:33489 +0.00011266336187471834 35495:35495 +0.00011266336187471834 60246:60246 +0.00011266336187471834 34730:34730 +0.00011266336187471834 58892:58892 +0.00011266336187471834 58890:58890 +0.00011266336187471834 58598:58598 +0.00011266336187471834 59692:59692 +0.00011266336187471834 59256:59256 +0.00011266336187471834 33957:33957 +0.00011266336187471834 60031:60031 +0.00011266336187471834 33175:33175 +0.00011266336187471834 60766:60766 +0.00011266336187471834 33432:33432 +0.00011266336187471834 33157:33157 +0.00011266336187471834 57920:57920 +0.00011266336187471834 34456:34456 +0.00011266336187471834 58198:58198 +0.00011266336187471834 58192:58192 +0.00011266336187471834 35023:35023 +0.00011266336187471834 35045:35045 +0.00011266336187471834 34187:34187 +0.00011266336187471834 56152:56152 +0.00011266336187471834 56104:56104 +0.00011266336187471834 33754:33754 +0.00011266336187471834 34340:34340 +0.00011266336187471834 57097:57097 +0.00011266336187471834 58189:58189 +0.00011266336187471834 57106:57106 +0.00011266336187471834 60808:60808 +0.00011266336187471834 57815:57815 +0.00011266336187471834 34608:34608 +0.00011266336187471834 57058:57058 +0.00011266336187471834 35328:35328 +0.00011266336187471834 35106:35106 +0.00011266336187471834 32818:32818 +0.00011266336187471834 58391:58391 +0.00011266336187471834 35132:35132 +0.00011266336187471834 60229:60229 +0.00011266336187471834 60776:60776 +0.00011266336187471834 35323:35323 +0.00011266336187471834 60643:60643 +0.00011266336187471834 35557:35557 +0.00011266336187471834 60764:60764 +0.00011266336187471834 56887:56887 +0.00011266336187471834 34636:34636 +0.00011266336187471834 59573:59573 +0.00011266336187471834 56394:56394 +0.00011266336187471834 59829:59829 +0.00011266336187471834 34852:34852 +0.00011266336187471834 35283:35283 +0.00011266336187471834 58052:58052 +0.00011266336187471834 57060:57060 +0.00011266336187471834 58351:58351 +0.00011266336187471834 56760:56760 +0.00011266336187471834 57303:57303 +0.00011266336187471834 35387:35387 +0.00011266336187471834 33763:33763 +0.00011266336187471834 59265:59265 +0.00011266336187471834 57055:57055 +0.00011266336187471834 59417:59417 +0.00011266336187471834 59037:59037 +0.00011266336187471834 59408:59408 +0.00011266336187471834 55854:55854 +0.00011266336187471834 33837:33837 +0.00011266336187471834 59800:59800 +0.00011266336187471834 33826:33826 +0.00011266336187471834 59447:59447 +0.00011266336187471834 59206:59206 +0.00011266336187471834 58416:58416 +0.00011266336187471834 34116:34116 +0.00011266336187471834 34958:34958 +0.00011266336187471834 33593:33593 +0.00011266336187471834 33289:33289 +0.00011266336187471834 60200:60200 +0.00011266336187471834 58389:58389 +0.00011266336187471834 57733:57733 +0.00011266336187471834 34216:34216 +0.00011266336187471834 33231:33231 +0.00011266336187471834 35204:35204 +0.00011266336187471834 59906:59906 +0.00011266336187471834 56553:56553 +0.00011266336187471834 56557:56557 +0.00011266336187471834 58038:58038 +0.00011266336187471834 58956:58956 +0.00011266336187471834 34087:34087 +0.00011266336187471834 58171:58171 +0.00011266336187471834 57664:57664 +0.00011266336187471834 56357:56357 +0.00011266336187471834 59196:59196 +0.00011266336187471834 32919:32919 +0.00011266336187471834 60214:60214 +0.00011266336187471834 55921:55921 +0.00011266336187471834 59139:59139 +0.00011266336187471834 56688:56688 +0.00011266336187471834 32961:32961 +0.00011266336187471834 33074:33074 +0.00011266336187471834 58661:58661 +0.00011266336187471834 59988:59988 +0.00011266336187471834 56910:56910 +0.00011266336187471834 56207:56207 +0.00011266336187471834 34645:34645 +0.00011266336187471834 33450:33450 +0.00011266336187471834 33719:33719 +0.00011266336187471834 34343:34343 +0.00011266336187471834 33347:33347 +0.00011266336187471834 58952:58952 +0.00011266336187471834 59703:59703 +0.00011266336187471834 33828:33828 +0.00011266336187471834 59123:59123 +0.00011266336187471834 56635:56635 +0.00011266336187471834 56945:56945 +0.00011266336187471834 56366:56366 +0.00011266336187471834 35256:35256 +0.00011266336187471834 57783:57783 +0.00011266336187471834 58111:58111 +0.00011266336187471834 60779:60779 +0.00011266336187471834 58939:58939 +0.00011266336187471834 57495:57495 +0.00011266336187471834 57995:57995 +0.00011266336187471834 56258:56258 +0.00011266336187471834 33064:33064 +0.00011266336187471834 58710:58710 +0.00011266336187471834 33160:33160 +0.00011266336187471834 60150:60150 +0.00011266336187471834 58597:58597 +0.00011266336187471834 55718:55718 +0.00011266336187471834 58138:58138 +0.00011266336187471834 56669:56669 +0.00011266336187471834 33149:33149 +0.00011266336187471834 58629:58629 +0.00011266336187471834 33084:33084 +0.00011266336187471834 35285:35285 +0.00011266336187471834 33457:33457 +0.00011266336187471834 60971:60971 +0.00011266336187471834 60191:60191 +0.00011266336187471834 35213:35213 +0.00011266336187471834 60895:60895 +0.00011266336187471834 58812:58812 +0.00011266336187471834 56021:56021 +0.00011266336187471834 35107:35107 +0.00011266336187471834 57072:57072 +0.00011266336187471834 55983:55983 +0.00011266336187471834 57358:57358 +0.00011266336187471834 55936:55936 +0.00011266336187471834 60239:60239 +0.00011266336187471834 55659:55659 +0.00011266336187471834 56885:56885 +0.00011266336187471834 59204:59204 +0.00011266336187471834 56290:56290 +0.00011266336187471834 60707:60707 +0.00011266336187471834 59855:59855 +0.00011266336187471834 57656:57656 +0.00011266336187471834 59956:59956 +0.00011266336187471834 59808:59808 +0.00011266336187471834 60608:60608 +0.00011266336187471834 57440:57440 +0.00011266336187471834 56268:56268 +0.00011266336187471834 58567:58567 +0.00011266336187471834 34665:34665 +0.00011266336187471834 33120:33120 +0.00011266336187471834 35246:35246 +0.00011266336187471834 33154:33154 +0.00011266336187471834 32886:32886 +0.00011266336187471834 56925:56925 +0.00011266336187471834 35192:35192 +0.00011266336187471834 34153:34153 +0.00011266336187471834 60405:60405 +0.00011266336187471834 55877:55877 +0.00011266336187471834 59847:59847 +0.00011266336187471834 33035:33035 +0.00011266336187471834 59217:59217 +0.00011266336187471834 58159:58159 +0.00011266336187471834 59035:59035 +0.00011266336187471834 32809:32809 +0.00011266336187471834 60098:60098 +0.00011266336187471834 59119:59119 +0.00011266336187471834 58792:58792 +0.00011266336187471834 57849:57849 +0.00011266336187471834 35354:35354 +0.00011266336187471834 60872:60872 +0.00011266336187471834 60774:60774 +0.00011266336187471834 60336:60336 +0.00011266336187471834 55893:55893 +0.00011266336187471834 60646:60646 +0.00011266336187471834 60136:60136 +0.00011266336187471834 60128:60128 +0.00011266336187471834 55852:55852 +0.00011266336187471834 60114:60114 +0.00011266336187471834 35265:35265 +0.00011266336187471834 57447:57447 +0.00011266336187471834 58882:58882 +0.00011266336187471834 57116:57116 +0.00011266336187471834 56769:56769 +0.00011266336187471834 59357:59357 +0.00011266336187471834 34342:34342 +0.00011266336187471834 33881:33881 +0.00011266336187471834 57333:57333 +0.00011266336187471834 58665:58665 +0.00011266336187471834 57624:57624 +0.00011266336187471834 57424:57424 +0.00011266336187471834 35244:35244 +0.00011266336187471834 58566:58566 +0.00011266336187471834 58496:58496 +0.00011266336187471834 33898:33898 +0.00011266336187471834 60050:60050 +0.00011266336187471834 56975:56975 +0.00011266336187471834 57532:57532 +0.00011266336187471834 57003:57003 +0.00011266336187471834 34717:34717 +0.00011266336187471834 33392:33392 +0.00011266336187471834 56115:56115 +0.00011266336187471834 59982:59982 +0.00011266336187471834 57937:57937 +0.00011266336187471834 35457:35457 +0.00011266336187471834 35291:35291 +0.00011266336187471834 58379:58379 +0.00011266336187471834 34724:34724 +0.00011266336187471834 34318:34318 +0.00011266336187471834 57680:57680 +0.00011266336187471834 60552:60552 +0.00011266336187471834 60041:60041 +0.00011266336187471834 58451:58451 +0.00011266336187471834 34770:34770 +0.00011266336187471834 33992:33992 +0.00011266336187471834 57350:57350 +0.00011266336187471834 56328:56328 +0.00011266336187471834 33873:33873 +0.00011266336187471834 32870:32870 +0.00011266336187471834 34793:34793 +0.00011266336187471834 59454:59454 +0.00011266336187471834 58184:58184 +0.00011266336187471834 60878:60878 +0.00011266336187471834 58332:58332 +0.00011266336187471834 34289:34289 +0.00011266336187471834 60062:60062 +0.00011266336187471834 56648:56648 +0.00011266336187471834 56732:56732 +0.00011266336187471834 55606:55606 +0.00011266336187471834 58206:58206 +0.00011266336187471834 32851:32851 +0.00011266336187471834 60329:60329 +0.00011266336187471834 57119:57119 +0.00011266336187471834 33244:33244 +0.00011266336187471834 58587:58587 +0.00011266336187471834 56782:56782 +0.00011266336187471834 35186:35186 +0.00011266336187471834 57766:57766 +0.00011266336187471834 33772:33772 +0.00011266336187471834 35079:35079 +0.00011266336187471834 60278:60278 +0.00011266336187471834 34784:34784 +0.00011266336187471834 33239:33239 +0.00011266336187471834 58076:58076 +0.00011266336187471834 58388:58388 +0.00011266336187471834 57080:57080 +0.00011266336187471834 33441:33441 +0.00011266336187471834 34513:34513 +0.00011266336187471834 55780:55780 +0.00011266336187471834 60577:60577 +0.00011266336187471834 57913:57913 +0.00011266336187471834 55722:55722 +0.00011266336187471834 35284:35284 +0.00011266336187471834 35114:35114 +0.00011266336187471834 56857:56857 +0.00011266336187471834 34541:34541 +0.00011266336187471834 32926:32926 +0.00011266336187471834 58447:58447 +0.00011266336187471834 57729:57729 +0.00011266336187471834 57524:57524 +0.00011266336187471834 56306:56306 +0.00011266336187471834 56512:56512 +0.00011266336187471834 58851:58851 +0.00011266336187471834 57797:57797 +0.00011266336187471834 58148:58148 +0.00011266336187471834 57545:57545 +0.00011266336187471834 35321:35321 +0.00011266336187471834 59838:59838 +0.00011266336187471834 33143:33143 +0.00011266336187471834 60095:60095 +0.00011266336187471834 57989:57989 +0.00011266336187471834 59124:59124 +0.00011266336187471834 58618:58618 +0.00011266336187471834 56967:56967 +0.00011266336187471834 59921:59921 +0.00011266336187471834 34252:34252 +0.00011266336187471834 56649:56649 +0.00011266336187471834 59201:59201 +0.00011266336187471834 35257:35257 +0.00011266336187471834 60637:60637 +0.00011266336187471834 58676:58676 +0.00011266336187471834 58252:58252 +0.00011266336187471834 57192:57192 +0.00011266336187471834 57082:57082 +0.00011266336187471834 55643:55643 +0.00011266336187471834 57694:57694 +0.00011266336187471834 55915:55915 +0.00011266336187471834 34207:34207 +0.00011266336187471834 57819:57819 +0.00011266336187471834 56548:56548 +0.00011266336187471834 33699:33699 +0.00011266336187471834 57465:57465 +0.00011266336187471834 56096:56096 +0.00011266336187471834 34180:34180 +0.00011266336187471834 33680:33680 +0.00011266336187471834 58186:58186 +0.00011266336187471834 33133:33133 +0.00011266336187471834 34282:34282 +0.00011266336187471834 60703:60703 +0.00011266336187471834 33124:33124 +0.00011266336187471834 60533:60533 +0.00011266336187471834 59320:59320 +0.00011266336187471834 34126:34126 +0.00011266336187471834 57531:57531 +0.00011266336187471834 33134:33134 +0.00011266336187471834 59996:59996 +0.00011266336187471834 58272:58272 +0.00011266336187471834 60783:60783 +0.00011266336187471834 59559:59559 +0.00011266336187471834 56693:56693 +0.00011266336187471834 60483:60483 +0.00011266336187471834 59503:59503 +0.00011266336187471834 33056:33056 +0.00011266336187471834 60850:60850 +0.00011266336187471834 60474:60474 +0.00011266336187471834 56151:56151 +0.00011266336187471834 35535:35535 +0.00011266336187471834 60236:60236 +0.00011266336187471834 56127:56127 +0.00011266336187471834 32881:32881 +0.00011266336187471834 56922:56922 +0.00011266336187471834 55935:55935 +0.00011266336187471834 57029:57029 +0.00011266336187471834 34824:34824 +0.00011266336187471834 35492:35492 +0.00011266336187471834 60028:60028 +0.00011266336187471834 59790:59790 +0.00011266336187471834 57203:57203 +0.00011266336187471834 55704:55704 +0.00011266336187471834 57474:57474 +0.00011266336187471834 56076:56076 +0.00011266336187471834 33381:33381 +0.00011266336187471834 58356:58356 +0.00011266336187471834 34778:34778 +0.00011266336187471834 34089:34089 +0.00011266336187471834 32930:32930 +0.00011266336187471834 57493:57493 +0.00011266336187471834 35546:35546 +0.00011266336187471834 32898:32898 +0.00011266336187471834 60384:60384 +0.00011266336187471834 59588:59588 +0.00011266336187471834 57331:57331 +0.00011266336187471834 57481:57481 +0.00011266336187471834 34978:34978 +0.00011266336187471834 58197:58197 +0.00011266336187471834 57343:57343 +0.00011266336187471834 35066:35066 +0.00011266336187471834 58798:58798 +0.00011266336187471834 33493:33493 +0.00011266336187471834 33023:33023 +0.00011266336187471834 55713:55713 +0.00011266336187471834 60945:60945 +0.00011266336187471834 57294:57294 +0.00011266336187471834 59117:59117 +0.00011266336187471834 60857:60857 +0.00011266336187471834 58520:58520 +0.00011266336187471834 34789:34789 +0.00011266336187471834 34386:34386 +0.00011266336187471834 56924:56924 +0.00011266336187471834 59911:59911 +0.00011266336187471834 57588:57588 +0.00011266336187471834 34241:34241 +0.00011266336187471834 35496:35496 +0.00011266336187471834 33198:33198 +0.00011266336187471834 60698:60698 +0.00011266336187471834 60162:60162 +0.00011266336187471834 34732:34732 +0.00011266336187471834 58459:58459 +0.00011266336187471834 56670:56670 +0.00011266336187471834 57442:57442 +0.00011266336187471834 34073:34073 +0.00011266336187471834 57226:57226 +0.00011266336187471834 58228:58228 +0.00011266336187471834 57730:57730 +0.00011266336187471834 56427:56427 +0.00011266336187471834 59450:59450 +0.00011266336187471834 57964:57964 +0.00011266336187471834 60250:60250 +0.00011266336187471834 32986:32986 +0.00011266336187471834 59781:59781 +0.00011266336187471834 56959:56959 +0.00011266336187471834 60163:60163 +0.00011266336187471834 56765:56765 +0.00011266336187471834 55762:55762 +0.00011266336187471834 57275:57275 +0.00011266336187471834 57507:57507 +0.00011266336187471834 34522:34522 +0.00011266336187471834 34352:34352 +0.00011266336187471834 33643:33643 +0.00011266336187471834 57045:57045 +0.00011266336187471834 60457:60457 +0.00011266336187471834 56848:56848 +0.00011266336187471834 33912:33912 +0.00011266336187471834 60811:60811 +0.00011266336187471834 58564:58564 +0.00011266336187471834 33468:33468 +0.00011266336187471834 35074:35074 +0.00011266336187471834 34230:34230 +0.00011266336187471834 32826:32826 +0.00011266336187471834 57511:57511 +0.00011266336187471834 58433:58433 +0.00011266336187471834 35206:35206 +0.00011266336187471834 34537:34537 +0.00011266336187471834 34935:34935 +0.00011266336187471834 58075:58075 +0.00011266336187471834 60135:60135 +0.00011266336187471834 58563:58563 +0.00011266336187471834 35276:35276 +0.00011266336187471834 59170:59170 +0.00011266336187471834 56620:56620 +0.00011266336187471834 55874:55874 +0.00011266336187471834 58254:58254 +0.00011266336187471834 58340:58340 +0.00011266336187471834 56249:56249 +0.00011266336187471834 34614:34614 +0.00011266336187471834 33889:33889 +0.00011266336187471834 32911:32911 +0.00011266336187471834 57686:57686 +0.00011266336187471834 56276:56276 +0.00011266336187471834 58030:58030 +0.00011266336187471834 35081:35081 +0.00011266336187471834 56776:56776 +0.00011266336187471834 57953:57953 +0.00011266336187471834 57085:57085 +0.00011266336187471834 35385:35385 +0.00011266336187471834 60487:60487 +0.00011266336187471834 58238:58238 +0.00011266336187471834 34892:34892 +0.00011266336187471834 34763:34763 +0.00011266336187471834 35466:35466 +0.00011266336187471834 60248:60248 +0.00011266336187471834 34933:34933 +0.00011266336187471834 58849:58849 +0.00011266336187471834 59129:59129 +0.00011266336187471834 55803:55803 +0.00011266336187471834 57108:57108 +0.00011266336187471834 57453:57453 +0.00011266336187471834 60917:60917 +0.00011266336187471834 32902:32902 +0.00011266336187471834 33603:33603 +0.00011266336187471834 34606:34606 +0.00011266336187471834 59798:59798 +0.00011266336187471834 56048:56048 +0.00011266336187471834 35548:35548 +0.00011266336187471834 59519:59519 +0.00011266336187471834 59728:59728 +0.00011266336187471834 59176:59176 +0.00011266336187471834 35516:35516 +0.00011266336187471834 34466:34466 +0.00011266336187471834 33572:33572 +0.00011266336187471834 58064:58064 +0.00011266336187471834 34902:34902 +0.00011266336187471834 58088:58088 +0.00011266336187471834 33130:33130 +0.00011266336187471834 55812:55812 +0.00011266336187471834 59429:59429 +0.00011266336187471834 35053:35053 +0.00011266336187471834 59349:59349 +0.00011266336187471834 56697:56697 +0.00011266336187471834 60814:60814 +0.00011266336187471834 34056:34056 +0.00011266336187471834 33095:33095 +0.00011266336187471834 59973:59973 +0.00011266336187471834 56497:56497 +0.00011266336187471834 35264:35264 +0.00011266336187471834 34602:34602 +0.00011266336187471834 33927:33927 +0.00011266336187471834 59894:59894 +0.00011266336187471834 58888:58888 +0.00011266336187471834 57614:57614 +0.00011266336187471834 56808:56808 +0.00011266336187471834 59392:59392 +0.00011266336187471834 57571:57571 +0.00011266336187471834 60479:60479 +0.00011266336187471834 59322:59322 +0.00011266336187471834 58153:58153 +0.00011266336187471834 34678:34678 +0.00011266336187471834 58403:58403 +0.00011266336187471834 56618:56618 +0.00011266336187471834 33751:33751 +0.00011266336187471834 35149:35149 +0.00011266336187471834 59967:59967 +0.00011266336187471834 59011:59011 +0.00011266336187471834 59405:59405 +0.00011266336187471834 58274:58274 +0.00011266336187471834 60476:60476 +0.00011266336187471834 58092:58092 +0.00011266336187471834 56770:56770 +0.00011266336187471834 34845:34845 +0.00011266336187471834 34233:34233 +0.00011266336187471834 60900:60900 +0.00011266336187471834 33971:33971 +0.00011266336187471834 33314:33314 +0.00011266336187471834 35217:35217 +0.00011266336187471834 58773:58773 +0.00011266336187471834 59235:59235 +0.00011266336187471834 58830:58830 +0.00011266336187471834 35386:35386 +0.00011266336187471834 60080:60080 +0.00011266336187471834 56727:56727 +0.00011266336187471834 35316:35316 +0.00011266336187471834 58840:58840 +0.00011266336187471834 33713:33713 +0.00011266336187471834 60503:60503 +0.00011266336187471834 57974:57974 +0.00011266336187471834 55617:55617 +0.00011266336187471834 59415:59415 +0.00011266336187471834 59510:59510 +0.00011266336187471834 59406:59406 +0.00011266336187471834 56354:56354 +0.00011266336187471834 32822:32822 +0.00011266336187471834 59841:59841 +0.00011266336187471834 57122:57122 +0.00011266336187471834 58273:58273 +0.00011266336187471834 34094:34094 +0.00011266336187471834 34284:34284 +0.00011266336187471834 34380:34380 +0.00011266336187471834 32948:32948 +0.00011266336187471834 56235:56235 +0.00011266336187471834 34649:34649 +0.00011266336187471834 56016:56016 +0.00011266336187471834 55796:55796 +0.00011266336187471834 58628:58628 +0.00011266336187471834 34470:34470 +0.00011266336187471834 60324:60324 +0.00011266336187471834 59882:59882 +0.00011266336187471834 57508:57508 +0.00011266336187471834 35421:35421 +0.00011266336187471834 60269:60269 +0.00011266336187471834 33002:33002 +0.00011266336187471834 59797:59797 +0.00011266336187471834 56952:56952 +0.00011266336187471834 35050:35050 +0.00011266336187471834 58484:58484 +0.00011266336187471834 32794:32794 +0.00011266336187471834 58842:58842 +0.00011266336187471834 34795:34795 +0.00011266336187471834 34915:34915 +0.00011266336187471834 34572:34572 +0.00011266336187471834 60017:60017 +0.00011266336187471834 58873:58873 +0.00011266336187471834 35547:35547 +0.00011266336187471834 34711:34711 +0.00011266336187471834 56332:56332 +0.00011266336187471834 33633:33633 +0.00011266336187471834 56192:56192 +0.00011266336187471834 56990:56990 +0.00011266336187471834 34644:34644 +0.00011266336187471834 33874:33874 +0.00011266336187471834 60465:60465 +0.00011266336187471834 58650:58650 +0.00011266336187471834 58506:58506 +0.00011266336187471834 57543:57543 +0.00011266336187471834 59540:59540 +0.00011266336187471834 35198:35198 +0.00011266336187471834 33533:33533 +0.00011266336187471834 60864:60864 +0.00011266336187471834 34209:34209 +0.00011266336187471834 58396:58396 +0.00011266336187471834 56011:56011 +0.00011266336187471834 34249:34249 +0.00011266336187471834 33317:33317 +0.00011266336187471834 57824:57824 +0.00011266336187471834 56676:56676 +0.00011266336187471834 59526:59526 +0.00011266336187471834 57760:57760 +0.00011266336187471834 35287:35287 +0.00011266336187471834 33520:33520 +0.00011266336187471834 60589:60589 +0.00011266336187471834 56496:56496 +0.00011266336187471834 56312:56312 +0.00011266336187471834 58535:58535 +0.00011266336187471834 56529:56529 +0.00011266336187471834 33243:33243 +0.00011266336187471834 60477:60477 +0.00011266336187471834 32770:32770 +0.00011266336187471834 33522:33522 +0.00011266336187471834 56920:56920 +0.00011266336187471834 60204:60204 +0.00011266336187471834 59960:59960 +0.00011266336187471834 58839:58839 +0.00011266336187471834 35413:35413 +0.00011266336187471834 35172:35172 +0.00011266336187471834 33896:33896 +0.00011266336187471834 57052:57052 +0.00011266336187471834 33464:33464 +0.00011266336187471834 59953:59953 +0.00011266336187471834 33388:33388 +0.00011266336187471834 33355:33355 +0.00011266336187471834 33986:33986 +0.00011266336187471834 33809:33809 +0.00011266336187471834 57230:57230 +0.00011266336187471834 59144:59144 +0.00011266336187471834 57851:57851 +0.00011266336187471834 33439:33439 +0.00011266336187471834 60557:60557 +0.00011266336187471834 56017:56017 +0.00011266336187471834 58806:58806 +0.00011266336187471834 57040:57040 +0.00011266336187471834 34981:34981 +0.00011266336187471834 34547:34547 +0.00011266336187471834 59333:59333 +0.00011266336187471834 58637:58637 +0.00011266336187471834 34232:34232 +0.00011266336187471834 56633:56633 +0.00011266336187471834 34454:34454 +0.00011266336187471834 34113:34113 +0.00011266336187471834 58850:58850 +0.00011266336187471834 34908:34908 +0.00011266336187471834 33929:33929 +0.00011266336187471834 34010:34010 +0.00011266336187471834 60271:60271 +0.00011266336187471834 58295:58295 +0.00011266336187471834 58706:58706 +0.00011266336187471834 56097:56097 +0.00011266336187471834 58277:58277 +0.00011266336187471834 35171:35171 +0.00011266336187471834 55680:55680 +0.00011266336187471834 35200:35200 +0.00011266336187471834 33901:33901 +0.00011266336187471834 60820:60820 +0.00011266336187471834 35036:35036 +0.00011266336187471834 59643:59643 +0.00011266336187471834 56901:56901 +0.00011266336187471834 59944:59944 +0.00011266336187471834 59127:59127 +0.00011266336187471834 55758:55758 +0.00011266336187471834 58507:58507 +0.00011266336187471834 33745:33745 +0.00011266336187471834 35461:35461 +0.00011266336187471834 33228:33228 +0.00011266336187471834 35292:35292 +0.00011266336187471834 57690:57690 +0.00011266336187471834 34880:34880 +0.00011266336187471834 58220:58220 +0.00011266336187471834 59177:59177 +0.00011266336187471834 56053:56053 +0.00011266336187471834 35281:35281 +0.00011266336187471834 35293:35293 +0.00011266336187471834 57837:57837 +0.00011266336187471834 57573:57573 +0.00011266336187471834 59846:59846 +0.00011266336187471834 56873:56873 +0.00011266336187471834 33664:33664 +0.00011266336187471834 56558:56558 +0.00011266336187471834 33676:33676 +0.00011266336187471834 58947:58947 +0.00011266336187471834 60843:60843 +0.00011266336187471834 57318:57318 +0.00011266336187471834 57209:57209 +0.00011266336187471834 34347:34347 +0.00011266336187471834 33418:33418 +0.00011266336187471834 35108:35108 +0.00011266336187471834 58417:58417 +0.00011266336187471834 57146:57146 +0.00011266336187471834 59018:59018 +0.00011266336187471834 57426:57426 +0.00011266336187471834 56472:56472 +0.00011266336187471834 60753:60753 +0.00011266336187471834 57864:57864 +0.00011266336187471834 57984:57984 +0.00011266336187471834 35098:35098 +0.00011266336187471834 34366:34366 +0.00011266336187471834 60536:60536 +0.00011266336187471834 60153:60153 +0.00011266336187471834 34500:34500 +0.00011266336187471834 33885:33885 +0.00011266336187471834 60353:60353 +0.00011266336187471834 58699:58699 +0.00011266336187471834 33985:33985 +0.00011266336187471834 58365:58365 +0.00011266336187471834 33323:33323 +0.00011266336187471834 59213:59213 +0.00011266336187471834 56180:56180 +0.00011266336187471834 34111:34111 +0.00011266336187471834 57942:57942 +0.00011266336187471834 34869:34869 +0.00011266336187471834 57574:57574 +0.00011266336187471834 60158:60158 +0.00011266336187471834 56721:56721 +0.00011266336187471834 35443:35443 +0.00011266336187471834 55795:55795 +0.00011266336187471834 35513:35513 +0.00011266336187471834 60471:60471 +0.00011266336187471834 59222:59222 +0.00011266336187471834 57196:57196 +0.00011266336187471834 57972:57972 +0.00011266336187471834 57190:57190 +0.00011266336187471834 57004:57004 +0.00011266336187471834 35130:35130 +0.00011266336187471834 35037:35037 +0.00011266336187471834 34520:34520 +0.00011266336187471834 60765:60765 +0.00011266336187471834 59713:59713 +0.00011266336187471834 59668:59668 +0.00011266336187471834 57595:57595 +0.00011266336187471834 59340:59340 +0.00011266336187471834 56370:56370 +0.00011266336187471834 56992:56992 +0.00011266336187471834 33540:33540 +0.00011266336187471834 59134:59134 +0.00011266336187471834 32934:32934 +0.00011266336187471834 34581:34581 +0.00011266336187471834 33288:33288 +0.00011266336187471834 57934:57934 +0.00011266336187471834 56511:56511 +0.00011266336187471834 60829:60829 +0.00011266336187471834 60371:60371 +0.00011266336187471834 59424:59424 +0.00011266336187471834 59160:59160 +0.00011266336187471834 34839:34839 +0.00011266336187471834 56353:56353 +0.00011266336187471834 55759:55759 +0.00011266336187471834 35047:35047 +0.00011266336187471834 35022:35022 +0.00011266336187471834 60011:60011 +0.00011266336187471834 60954:60954 +0.00011266336187471834 33997:33997 +0.00011266336187471834 57050:57050 +0.00011266336187471834 60423:60423 +0.00011266336187471834 56772:56772 +0.00011266336187471834 33088:33088 +0.00011266336187471834 60520:60520 +0.00011266336187471834 57914:57914 +0.00011266336187471834 55913:55913 +0.00011266336187471834 56771:56771 +0.00011266336187471834 35004:35004 +0.00011266336187471834 56961:56961 +0.00011266336187471834 60409:60409 +0.00011266336187471834 57906:57906 +0.00011266336187471834 56932:56932 +0.00011266336187471834 58716:58716 +0.00011266336187471834 58211:58211 +0.00011266336187471834 56514:56514 +0.00011266336187471834 57572:57572 +0.00011266336187471834 55789:55789 +0.00011266336187471834 60713:60713 +0.00011266336187471834 33456:33456 +0.00011266336187471834 35542:35542 +0.00011266336187471834 34400:34400 +0.00011266336187471834 58214:58214 +0.00011266336187471834 55828:55828 +0.00011266336187471834 34458:34458 +0.00011266336187471834 58914:58914 +0.00011266336187471834 60321:60321 +0.00011266336187471834 55792:55792 +0.00011266336187471834 35014:35014 +0.00011266336187471834 59539:59539 +0.00011266336187471834 59161:59161 +0.00011266336187471834 33804:33804 +0.00011266336187471834 58404:58404 +0.00011266336187471834 57829:57829 +0.00011266336187471834 60605:60605 +0.00011266336187471834 59623:59623 +0.00011266336187471834 56334:56334 +0.00011266336187471834 56224:56224 +0.00011266336187471834 56213:56213 +0.00011266336187471834 57473:57473 +0.00011266336187471834 57769:57769 +0.00011266336187471834 60697:60697 +0.00011266336187471834 33258:33258 +0.00011266336187471834 59789:59789 +0.00011266336187471834 55711:55711 +0.00011266336187471834 59814:59814 +0.00011266336187471834 34934:34934 +0.00011266336187471834 59719:59719 +0.00011266336187471834 57102:57102 +0.00011266336187471834 34598:34598 +0.00011266336187471834 58421:58421 +0.00011266336187471834 34009:34009 +0.00011266336187471834 59671:59671 +0.00011266336187471834 57928:57928 +0.00011266336187471834 56283:56283 +0.00011266336187471834 57412:57412 +0.00011266336187471834 60922:60922 +0.00011266336187471834 60532:60532 +0.00011266336187471834 56652:56652 +0.00011266336187471834 34250:34250 +0.00011266336187471834 35377:35377 +0.00011266336187471834 34412:34412 +0.00011266336187471834 58735:58735 +0.00011266336187471834 56445:56445 +0.00011266336187471834 33854:33854 +0.00011266336187471834 33466:33466 +0.00011266336187471834 32938:32938 +0.00011266336187471834 32901:32901 +0.00011266336187471834 59077:59077 +0.00011266336187471834 57066:57066 +0.00011266336187471834 34938:34938 +0.00011266336187471834 59709:59709 +0.00011266336187471834 56668:56668 +0.00011266336187471834 33171:33171 +0.00011266336187471834 59550:59550 +0.00011266336187471834 60385:60385 +0.00011266336187471834 59895:59895 +0.00011266336187471834 57695:57695 +0.00011266336187471834 57788:57788 +0.00011266336187471834 35404:35404 +0.00011266336187471834 34102:34102 +0.00011266336187471834 33925:33925 +0.00011266336187471834 60491:60491 +0.00011266336187471834 58739:58739 +0.00011266336187471834 59477:59477 +0.00011266336187471834 57715:57715 +0.00011266336187471834 55979:55979 +0.00011266336187471834 59525:59525 +0.00011266336187471834 58157:58157 +0.00011266336187471834 34479:34479 +0.00011266336187471834 60967:60967 +0.00011266336187471834 58823:58823 +0.00011266336187471834 59961:59961 +0.00011266336187471834 33277:33277 +0.00011266336187471834 33012:33012 +0.00011266336187471834 57138:57138 +0.00011266336187471834 56210:56210 +0.00011266336187471834 35026:35026 +0.00011266336187471834 33051:33051 +0.00011266336187471834 57132:57132 +0.00011266336187471834 57625:57625 +0.00011266336187471834 58905:58905 +0.00011266336187471834 55610:55610 +0.00011266336187471834 34155:34155 +0.00011266336187471834 33635:33635 +0.00011266336187471834 58757:58757 +0.00011266336187471834 56338:56338 +0.00011266336187471834 33600:33600 +0.00011266336187471834 34927:34927 +0.00011266336187471834 33447:33447 +0.00011266336187471834 58515:58515 +0.00011266336187471834 34656:34656 +0.00011266336187471834 33479:33479 +0.00011266336187471834 59347:59347 +0.00011266336187471834 34029:34029 +0.00011266336187471834 57759:57759 +0.00011266336187471834 59617:59617 +0.00011266336187471834 59569:59569 +0.00011266336187471834 33783:33783 +0.00011266336187471834 57589:57589 +0.00011266336187471834 56712:56712 +0.00011266336187471834 59897:59897 +0.00011266336187471834 34648:34648 +0.00011266336187471834 56777:56777 +0.00011266336187471834 56317:56317 +0.00011266336187471834 60632:60632 +0.00011266336187471834 33006:33006 +0.00011266336187471834 32972:32972 +0.00011266336187471834 59945:59945 +0.00011266336187471834 34828:34828 +0.00011266336187471834 57548:57548 +0.00011266336187471834 57422:57422 +0.00011266336187471834 58233:58233 +0.00011266336187471834 56979:56979 +0.00011266336187471834 34944:34944 +0.00011266336187471834 34378:34378 +0.00011266336187471834 33333:33333 +0.00011266336187471834 59062:59062 +0.00011266336187471834 34762:34762 +0.00011266336187471834 58855:58855 +0.00011266336187471834 56376:56376 +0.00011266336187471834 33770:33770 +0.00011266336187471834 34220:34220 +0.00011266336187471834 57623:57623 +0.00011266336187471834 58164:58164 +0.00011266336187471834 56942:56942 +0.00011266336187471834 33351:33351 +0.00011266336187471834 57712:57712 +0.00011266336187471834 57128:57128 +0.00011266336187471834 33295:33295 +0.00011266336187471834 56883:56883 +0.00011266336187471834 33906:33906 +0.00011266336187471834 60909:60909 +0.00011266336187471834 56616:56616 +0.00011266336187471834 32833:32833 +0.00011266336187471834 57185:57185 +0.00011266336187471834 32782:32782 +0.00011266336187471834 59191:59191 +0.00011266336187471834 60731:60731 +0.00011266336187471834 58843:58843 +0.00011266336187471834 58487:58487 +0.00011266336187471834 56168:56168 +0.00011266336187471834 33269:33269 +0.00011266336187471834 59427:59427 +0.00011266336187471834 34532:34532 +0.00011266336187471834 33364:33364 +0.00011266336187471834 34759:34759 +0.00011266336187471834 60484:60484 +0.00011266336187471834 56522:56522 +0.00011266336187471834 59169:59169 +0.00011266336187471834 60137:60137 +0.00011266336187471834 57945:57945 +0.00011266336187471834 56583:56583 +0.00011266336187471834 57225:57225 +0.00011266336187471834 33144:33144 +0.00011266336187471834 60998:60998 +0.00011266336187471834 56734:56734 +0.00011266336187471834 59879:59879 +0.00011266336187471834 56663:56663 +0.00011266336187471834 58154:58154 +0.00011266336187471834 57379:57379 +0.00011266336187471834 57086:57086 +0.00011266336187471834 57533:57533 +0.00011266336187471834 57007:57007 +0.00011266336187471834 56778:56778 +0.00011266336187471834 59391:59391 +0.00011266336187471834 32916:32916 +0.00011266336187471834 32896:32896 +0.00011266336187471834 59203:59203 +0.00011266336187471834 60554:60554 +0.00011266336187471834 34925:34925 +0.00011266336187471834 32994:32994 +0.00011266336187471834 60995:60995 +0.00011266336187471834 59317:59317 +0.00011266336187471834 35059:35059 +0.00011266336187471834 33659:33659 +0.00011266336187471834 58581:58581 +0.00011266336187471834 56023:56023 +0.00011266336187471834 59562:59562 +0.00011266336187471834 56007:56007 +0.00011266336187471834 34689:34689 +0.00011266336187471834 56110:56110 +0.00011266336187471834 32889:32889 +0.00011266336187471834 33808:33808 +0.00011266336187471834 60283:60283 +0.00011266336187471834 57232:57232 +0.00011266336187471834 57770:57770 +0.00011266336187471834 33650:33650 +0.00011266336187471834 33226:33226 +0.00011266336187471834 59884:59884 +0.00011266336187471834 56940:56940 +0.00011266336187471834 57758:57758 +0.00011266336187471834 35174:35174 +0.00011266336187471834 60043:60043 +0.00011266336187471834 58531:58531 +0.00011266336187471834 57144:57144 +0.00011266336187471834 34020:34020 +0.00011266336187471834 56928:56928 +0.00011266336187471834 55992:55992 +0.00011266336187471834 57628:57628 +0.00011266336187471834 35432:35432 +0.00011266336187471834 33039:33039 +0.00011266336187471834 60148:60148 +0.00011266336187471834 59954:59954 +0.00011266336187471834 58689:58689 +0.00011266336187471834 56117:56117 +0.00011266336187471834 59534:59534 +0.00011266336187471834 34560:34560 +0.00011266336187471834 33255:33255 +0.00011266336187471834 58815:58815 +0.00011266336187471834 33047:33047 +0.00011266336187471834 58395:58395 +0.00011266336187471834 34813:34813 +0.00011266336187471834 56262:56262 +0.00011266336187471834 57871:57871 +0.00011266336187471834 60926:60926 +0.00011266336187471834 60197:60197 +0.00011266336187471834 35478:35478 +0.00011266336187471834 34190:34190 +0.00011266336187471834 55805:55805 +0.00011266336187471834 60245:60245 +0.00011266336187471834 59092:59092 +0.00011266336187471834 33141:33141 +0.00011266336187471834 34643:34643 +0.00011266336187471834 58325:58325 +0.00011266336187471834 59516:59516 +0.00011266336187471834 60992:60992 +0.00011266336187471834 60849:60849 +0.00011266336187471834 58822:58822 +0.00011266336187471834 57789:57789 +0.00011266336187471834 57407:57407 +0.00011266336187471834 58577:58577 +0.00011266336187471834 58331:58331 +0.00011266336187471834 60684:60684 +0.00011266336187471834 59278:59278 +0.00011266336187471834 58307:58307 +0.00011266336187471834 33836:33836 +0.00011266336187471834 58561:58561 +0.00011266336187471834 57156:57156 +0.00011266336187471834 35319:35319 +0.00011266336187471834 59151:59151 +0.00011266336187471834 57812:57812 +0.00011266336187471834 56707:56707 +0.00011266336187471834 34705:34705 +0.00011266336187471834 59465:59465 +0.00011266336187471834 57893:57893 +0.00011266336187471834 34527:34527 +0.00011266336187471834 59933:59933 +0.00011266336187471834 57155:57155 +0.00011266336187471834 56994:56994 +0.00011266336187471834 33596:33596 +0.00011266336187471834 35267:35267 +0.00011266336187471834 34273:34273 +0.00011266336187471834 59563:59563 +0.00011266336187471834 58344:58344 +0.00011266336187471834 57239:57239 +0.00011266336187471834 34196:34196 +0.00011266336187471834 56031:56031 +0.00011266336187471834 55716:55716 +0.00011266336187471834 57504:57504 +0.00011266336187471834 35462:35462 +0.00011266336187471834 57781:57781 +0.00011266336187471834 60144:60144 +0.00011266336187471834 34034:34034 +0.00011266336187471834 57569:57569 +0.00011266336187471834 56717:56717 +0.00011266336187471834 60555:60555 +0.00011266336187471834 33460:33460 +0.00011266336187471834 32914:32914 +0.00011266336187471834 56779:56779 +0.00011266336187471834 60669:60669 +0.00011266336187471834 59578:59578 +0.00011266336187471834 57183:57183 +0.00011266336187471834 57145:57145 +0.00011266336187471834 33959:33959 +0.00011266336187471834 60583:60583 +0.00011266336187471834 59787:59787 +0.00011266336187471834 32996:32996 +0.00011266336187471834 34396:34396 +0.00011266336187471834 34007:34007 +0.00011266336187471834 56741:56741 +0.00011266336187471834 58217:58217 +0.00011266336187471834 34631:34631 +0.00011266336187471834 34800:34800 +0.00011266336187471834 59955:59955 +0.00011266336187471834 35117:35117 +0.00011266336187471834 60451:60451 +0.00011266336187471834 56453:56453 +0.00011266336187471834 33416:33416 +0.00011266336187471834 56463:56463 +0.00011266336187471834 35390:35390 +0.00011266336187471834 35159:35159 +0.00011266336187471834 34736:34736 +0.00011266336187471834 60899:60899 +0.00011266336187471834 59687:59687 +0.00011266336187471834 59479:59479 +0.00011266336187471834 33820:33820 +0.00011266336187471834 57681:57681 +0.00011266336187471834 57710:57710 +0.00011266336187471834 56542:56542 +0.00011266336187471834 60611:60611 +0.00011266336187471834 59332:59332 +0.00011266336187471834 59759:59759 +0.00011266336187471834 59331:59331 +0.00011266336187471834 34507:34507 +0.00011266336187471834 60948:60948 +0.00011266336187471834 34995:34995 +0.00011266336187471834 33742:33742 +0.00011266336187471834 60624:60624 +0.00011266336187471834 59987:59987 +0.00011266336187471834 34701:34701 +0.00011266336187471834 34921:34921 +0.00011266336187471834 60937:60937 +0.00011266336187471834 60097:60097 +0.00011266336187471834 57075:57075 +0.00011266336187471834 34706:34706 +0.00011266336187471834 34317:34317 +0.00011266336187471834 60235:60235 +0.00011266336187471834 59455:59455 +0.00011266336187471834 32795:32795 +0.00011266336187471834 59624:59624 +0.00011266336187471834 59042:59042 +0.00011266336187471834 56175:56175 +0.00011266336187471834 60683:60683 +0.00011266336187471834 34445:34445 +0.00011266336187471834 60482:60482 +0.00011266336187471834 57409:57409 +0.00011266336187471834 60171:60171 +0.00011266336187471834 34235:34235 +0.00011266336187471834 34959:34959 +0.00011266336187471834 58467:58467 +0.00011266336187471834 57304:57304 +0.00011266336187471834 59255:59255 +0.00011266336187471834 55898:55898 +0.00011266336187471834 60528:60528 +0.00011266336187471834 57421:57421 +0.00011266336187471834 33875:33875 +0.00011266336187471834 58728:58728 +0.00011266336187471834 57371:57371 +0.00011266336187471834 33341:33341 +0.00011266336187471834 58623:58623 +0.00011266336187471834 56660:56660 +0.00011266336187471834 56759:56759 +0.00011266336187471834 35169:35169 +0.00011266336187471834 33657:33657 +0.00011266336187471834 59386:59386 +0.00011266336187471834 57170:57170 +0.00011266336187471834 33096:33096 +0.00011266336187471834 60518:60518 +0.00011266336187471834 58512:58512 +0.00011266336187471834 59926:59926 +0.00011266336187471834 59934:59934 +0.00011266336187471834 56728:56728 +0.00011266336187471834 34804:34804 +0.00011266336187471834 59893:59893 +0.00011266336187471834 57362:57362 +0.00011266336187471834 57112:57112 +0.00011266336187471834 56105:56105 +0.00011266336187471834 34023:34023 +0.00011266336187471834 32990:32990 +0.00011266336187471834 59010:59010 +0.00011266336187471834 58803:58803 +0.00011266336187471834 56624:56624 +0.00011266336187471834 60133:60133 +0.00011266336187471834 60320:60320 +0.00011266336187471834 35528:35528 +0.00011266336187471834 57711:57711 +0.00011266336187471834 56790:56790 +0.00011266336187471834 56919:56919 +0.00011266336187471834 57784:57784 +0.00011266336187471834 33208:33208 +0.00011266336187471834 56478:56478 +0.00011266336187471834 34174:34174 +0.00011266336187471834 58207:58207 +0.00011266336187471834 60793:60793 +0.00011266336187471834 60264:60264 +0.00011266336187471834 33691:33691 +0.00011266336187471834 58128:58128 +0.00011266336187471834 57337:57337 +0.00011266336187471834 34557:34557 +0.00011266336187471834 32935:32935 +0.00011266336187471834 55609:55609 +0.00011266336187471834 34057:34057 +0.00011266336187471834 33303:33303 +0.00011266336187471834 59702:59702 +0.00011266336187471834 58000:58000 +0.00011266336187471834 35166:35166 +0.00011266336187471834 56978:56978 +0.00011266336187471834 56666:56666 +0.00011266336187471834 60853:60853 +0.00011266336187471834 59502:59502 +0.00011266336187471834 55706:55706 +0.00011266336187471834 58212:58212 +0.00011266336187471834 34963:34963 +0.00011266336187471834 55894:55894 +0.00011266336187471834 33541:33541 +0.00011266336187471834 33535:33535 +0.00011266336187471834 33497:33497 +0.00011266336187471834 59109:59109 +0.00011266336187471834 55963:55963 +0.00011266336187471834 34305:34305 +0.00011266336187471834 57961:57961 +0.00011266336187471834 60569:60569 +0.00011266336187471834 60599:60599 +0.00011266336187471834 59751:59751 +0.00011266336187471834 57698:57698 +0.00011266336187471834 59226:59226 +0.00011266336187471834 57115:57115 +0.00011266336187471834 35555:35555 +0.00011266336187471834 33389:33389 +0.00011266336187471834 57521:57521 +0.00011266336187471834 35104:35104 +0.00011266336187471834 56564:56564 +0.00011266336187471834 56437:56437 +0.00011266336187471834 57607:57607 +0.00011266336187471834 58671:58671 +0.00011266336187471834 55923:55923 +0.00011266336187471834 60708:60708 +0.00011266336187471834 35105:35105 +0.00011266336187471834 56650:56650 +0.00011266336187471834 32847:32847 +0.00011266336187471834 33080:33080 +0.00011266336187471834 56493:56493 +0.00011266336187471834 55865:55865 +0.00011266336187471834 35419:35419 +0.00011266336187471834 60178:60178 +0.00011266336187471834 35541:35541 +0.00011266336187471834 60393:60393 +0.00011266336187471834 33099:33099 +0.00011266336187471834 60903:60903 +0.00011266336187471834 56809:56809 +0.00011266336187471834 35376:35376 +0.00011266336187471834 34118:34118 +0.00011266336187471834 57938:57938 +0.00011266336187471834 59980:59980 +0.00011266336187471834 57099:57099 +0.00011266336187471834 34106:34106 +0.00011266336187471834 60588:60588 +0.00011266336187471834 60311:60311 +0.00011266336187471834 57357:57357 +0.00011266336187471834 57459:57459 +0.00011266336187471834 58334:58334 +0.00011266336187471834 56270:56270 +0.00011266336187471834 35428:35428 +0.00011266336187471834 34298:34298 +0.00011266336187471834 60907:60907 +0.00011266336187471834 60595:60595 +0.00011266336187471834 58595:58595 +0.00011266336187471834 34270:34270 +0.00011266336187471834 58874:58874 +0.00011266336187471834 60752:60752 +0.00011266336187471834 59522:59522 +0.00011266336187471834 58478:58478 +0.00011266336187471834 35227:35227 +0.00011266336187471834 33683:33683 +0.00011266336187471834 57463:57463 +0.00011266336187471834 60991:60991 +0.00011266336187471834 56406:56406 +0.00011266336187471834 56128:56128 +0.00011266336187471834 33204:33204 +0.00011266336187471834 56630:56630 +0.00011266336187471834 58162:58162 +0.00011266336187471834 34734:34734 +0.00011266336187471834 57879:57879 +0.00011266336187471834 34551:34551 +0.00011266336187471834 60433:60433 +0.00011266336187471834 33956:33956 +0.00011266336187471834 58753:58753 +0.00011266336187471834 34295:34295 +0.00011266336187471834 59712:59712 +0.00011266336187471834 57204:57204 +0.00011266336187471834 56955:56955 +0.00011266336187471834 56349:56349 +0.00011266336187471834 34601:34601 +0.00011266336187471834 34947:34947 +0.00011266336187471834 60956:60956 +0.00011266336187471834 34912:34912 +0.00011266336187471834 34254:34254 +0.00011266336187471834 58237:58237 +0.00011266336187471834 56653:56653 +0.00011266336187471834 60759:60759 +0.00011266336187471834 60445:60445 +0.00011266336187471834 60408:60408 +0.00011266336187471834 58333:58333 +0.00011266336187471834 59660:59660 +0.00011266336187471834 34864:34864 +0.00011266336187471834 55850:55850 +0.00011266336187471834 60361:60361 +0.00011266336187471834 58024:58024 +0.00011266336187471834 34293:34293 +0.00011266336187471834 34957:34957 +0.00011266336187471834 34399:34399 +0.00011266336187471834 59511:59511 +0.00011266336187471834 35380:35380 +0.00011266336187471834 60839:60839 +0.00011266336187471834 56491:56491 +0.00011266336187471834 34673:34673 +0.00011266336187471834 60891:60891 +0.00011266336187471834 59810:59810 +0.00011266336187471834 35486:35486 +0.00011266336187471834 58865:58865 +0.00011266336187471834 33397:33397 +0.00011266336187471834 33210:33210 +0.00011266336187471834 58347:58347 +0.00011266336187471834 56433:56433 +0.00011266336187471834 57814:57814 +0.00011266336187471834 35220:35220 +0.00011266336187471834 35176:35176 +0.00011266336187471834 59032:59032 +0.00011266336187471834 59767:59767 +0.00011266336187471834 35161:35161 +0.00011266336187471834 60919:60919 +0.00011266336187471834 34707:34707 +0.00011266336187471834 34398:34398 +0.00011266336187471834 32955:32955 +0.00011266336187471834 60659:60659 +0.00011266336187471834 34571:34571 +0.00011266336187471834 33841:33841 +0.00011266336187471834 58996:58996 +0.00011266336187471834 55727:55727 +0.00011266336187471834 60538:60538 +0.00011266336187471834 60510:60510 +0.00011266336187471834 58960:58960 +0.00011266336187471834 58954:58954 +0.00011266336187471834 55868:55868 +0.00011266336187471834 59280:59280 +0.00011266336187471834 56209:56209 +0.00011266336187471834 55993:55993 +0.00011266336187471834 34740:34740 +0.00011266336187471834 33723:33723 +0.00011266336187471834 33232:33232 +0.00011266336187471834 59111:59111 +0.00011266336187471834 34579:34579 +0.00011266336187471834 56143:56143 +0.00011266336187471834 57668:57668 +0.00011266336187471834 56240:56240 +0.00011266336187471834 55752:55752 +0.00011266336187471834 34716:34716 +0.00011266336187471834 34042:34042 +0.00011266336187471834 60950:60950 +0.00011266336187471834 57732:57732 +0.00011266336187471834 57130:57130 +0.00011266336187471834 34236:34236 +0.00011266336187471834 59313:59313 +0.00011266336187471834 57305:57305 +0.00011266336187471834 34597:34597 +0.00011266336187471834 33375:33375 +0.00011266336187471834 34251:34251 +0.00011266336187471834 33658:33658 +0.00011266336187471834 32780:32780 +0.00011266336187471834 59902:59902 +0.00011266336187471834 58536:58536 +0.00011266336187471834 34948:34948 +0.00011266336187471834 34002:34002 +0.00011266336187471834 56158:56158 +0.00011266336187471834 56287:56287 +0.00011266336187471834 56898:56898 +0.00011266336187471834 35417:35417 +0.00011266336187471834 59017:59017 +0.00011266336187471834 35151:35151 +0.00011266336187471834 33112:33112 +0.00011266336187471834 58370:58370 +0.00011266336187471834 35366:35366 +0.00011266336187471834 60714:60714 +0.00011266336187471834 58319:58319 +0.00011266336187471834 35494:35494 +0.00011266336187471834 34486:34486 +0.00011266336187471834 34370:34370 +0.00011266336187471834 55882:55882 +0.00011266336187471834 34745:34745 +0.00011266336187471834 35338:35338 +0.00011266336187471834 60618:60618 +0.00011266336187471834 59667:59667 +0.00011266336187471834 33487:33487 +0.00011266336187471834 60871:60871 +0.00011266336187471834 57640:57640 +0.00011266336187471834 34290:34290 +0.00011266336187471834 56221:56221 +0.00011266336187471834 33687:33687 +0.00011266336187471834 60375:60375 +0.00011266336187471834 35449:35449 +0.00011266336187471834 59147:59147 +0.00011266336187471834 56594:56594 +0.00011266336187471834 34308:34308 +0.00011266336187471834 59506:59506 +0.00011266336187471834 55940:55940 +0.00011266336187471834 60287:60287 +0.00011266336187471834 55928:55928 +0.00011266336187471834 58574:58574 +0.00011266336187471834 60804:60804 +0.00011266336187471834 56399:56399 +0.00011266336187471834 33668:33668 +0.00011266336187471834 56323:56323 +0.00011266336187471834 59416:59416 +0.00011266336187471834 58203:58203 +0.00011266336187471834 57811:57811 +0.00011266336187471834 57093:57093 +0.00011266336187471834 35109:35109 +0.00011266336187471834 33135:33135 +0.00011266336187471834 60745:60745 +0.00011266336187471834 33316:33316 +0.00011266336187471834 55804:55804 +0.00011266336187471834 56724:56724 +0.00011266336187471834 59940:59940 +0.00011266336187471834 33061:33061 +0.00011266336187471834 57830:57830 +0.00011266336187471834 58580:58580 +0.00011266336187471834 32836:32836 +0.00011266336187471834 58267:58267 +0.00011266336187471834 59925:59925 +0.00011266336187471834 59786:59786 +0.00011266336187471834 35067:35067 +0.00011266336187471834 58733:58733 +0.00011266336187471834 56658:56658 +0.00011266336187471834 33579:33579 +0.00011266336187471834 58734:58734 +0.00011266336187471834 56295:56295 +0.00011266336187471834 56572:56572 +0.00011266336187471834 60014:60014 +0.00011266336187471834 34753:34753 +0.00011266336187471834 58280:58280 +0.00011266336187471834 57384:57384 +0.00011266336187471834 33563:33563 +0.00011266336187471834 57338:57338 +0.00011266336187471834 56917:56917 +0.00011266336187471834 56579:56579 +0.00011266336187471834 33046:33046 +0.00011266336187471834 58971:58971 +0.00011266336187471834 33420:33420 +0.00011266336187471834 57166:57166 +0.00011266336187471834 34092:34092 +0.00011266336187471834 58731:58731 +0.00011266336187471834 60319:60319 +0.00011266336187471834 56447:56447 +0.00011266336187471834 55872:55872 +0.00011266336187471834 60990:60990 +0.00011266336187471834 35260:35260 +0.00011266336187471834 59483:59483 +0.00011266336187471834 58509:58509 +0.00011266336187471834 34894:34894 +0.00011266336187471834 32828:32828 +0.00011266336187471834 58708:58708 +0.00011266336187471834 58653:58653 +0.00011266336187471834 56382:56382 +0.00011266336187471834 59104:59104 +0.00011266336187471834 59505:59505 +0.00011266336187471834 59112:59112 +0.00011266336187471834 34259:34259 +0.00011266336187471834 33647:33647 +0.00011266336187471834 60434:60434 +0.00011266336187471834 34826:34826 +0.00011266336187471834 55914:55914 +0.00011266336187471834 60748:60748 +0.00011266336187471834 57903:57903 +0.00011266336187471834 58316:58316 +0.00011266336187471834 56142:56142 +0.00011266336187471834 56131:56131 +0.00011266336187471834 35209:35209 +0.00011266336187471834 56559:56559 +0.00011266336187471834 59302:59302 +0.00011266336187471834 33142:33142 +0.00011266336187471834 59012:59012 +0.00011266336187471834 33855:33855 +0.00011266336187471834 60633:60633 +0.00011266336187471834 57705:57705 +0.00011266336187471834 33747:33747 +0.00011266336187471834 58758:58758 +0.00011266336187471834 59107:59107 +0.00011266336187471834 58045:58045 +0.00011266336187471834 33532:33532 +0.00011266336187471834 35467:35467 +0.00011266336187471834 56440:56440 +0.00011266336187471834 33483:33483 +0.00011266336187471834 58902:58902 +0.00011266336187471834 60796:60796 +0.00011266336187471834 60358:60358 +0.00011266336187471834 35509:35509 +0.00011266336187471834 34471:34471 +0.00011266336187471834 59446:59446 +0.00011266336187471834 34355:34355 +0.00011266336187471834 33188:33188 +0.00011266336187471834 57021:57021 +0.00011266336187471834 34336:34336 +0.00011266336187471834 57858:57858 +0.00011266336187471834 58558:58558 +0.00011266336187471834 35418:35418 +0.00011266336187471834 57611:57611 +0.00011266336187471834 57237:57237 +0.00011266336187471834 33645:33645 +0.00011266336187471834 57446:57446 +0.00011266336187471834 59908:59908 +0.00011266336187471834 58643:58643 +0.00011266336187471834 56263:56263 +0.00011266336187471834 59426:59426 +0.00011266336187471834 32967:32967 +0.00011266336187471834 33651:33651 +0.00011266336187471834 58476:58476 +0.00011266336187471834 34910:34910 +0.00011266336187471834 56598:56598 +0.00011266336187471834 34965:34965 +0.00011266336187471834 33068:33068 +0.00011266336187471834 59718:59718 +0.00011266336187471834 57767:57767 +0.00011266336187471834 56420:56420 +0.00011266336187471834 60426:60426 +0.00011266336187471834 58384:58384 +0.00011266336187471834 33822:33822 +0.00011266336187471834 33578:33578 +0.00011266336187471834 56819:56819 +0.00011266336187471834 58554:58554 +0.00011266336187471834 60656:60656 +0.00011266336187471834 57094:57094 +0.00011266336187471834 56745:56745 +0.00011266336187471834 33319:33319 +0.00011266336187471834 57194:57194 +0.00011266336187471834 55885:55885 +0.00011266336187471834 59451:59451 +0.00011266336187471834 59028:59028 +0.00011266336187471834 55843:55843 +0.00011266336187471834 34197:34197 +0.00011266336187471834 32892:32892 +0.00011266336187471834 60769:60769 +0.00011266336187471834 59682:59682 +0.00011266336187471834 33033:33033 +0.00011266336187471834 60781:60781 +0.00011266336187471834 34634:34634 +0.00011266336187471834 33197:33197 +0.00011266336187471834 32920:32920 +0.00011266336187471834 57639:57639 +0.00011266336187471834 59099:59099 +0.00011266336187471834 59631:59631 +0.00011266336187471834 55670:55670 +0.00011266336187471834 57182:57182 +0.00011266336187471834 60027:60027 +0.00011266336187471834 56508:56508 +0.00011266336187471834 57485:57485 +0.00011266336187471834 56138:56138 +0.00011266336187471834 34356:34356 +0.00011266336187471834 33283:33283 +0.00011266336187471834 34294:34294 +0.00011266336187471834 60220:60220 +0.00011266336187471834 59164:59164 +0.00011266336187471834 57538:57538 +0.00011266336187471834 55797:55797 +0.00011266336187471834 55624:55624 +0.00011266336187471834 59524:59524 +0.00011266336187471834 56982:56982 +0.00011266336187471834 33038:33038 +0.00011266336187471834 57005:57005 +0.00011266336187471834 56303:56303 +0.00011266336187471834 57962:57962 +0.00011266336187471834 33604:33604 +0.00011266336187471834 33242:33242 +0.00011266336187471834 58283:58283 +0.00011266336187471834 59202:59202 +0.00011266336187471834 56862:56862 +0.00011266336187471834 35514:35514 +0.00011266336187471834 34901:34901 +0.00011266336187471834 60930:60930 +0.00011266336187471834 35211:35211 +0.00011266336187471834 60084:60084 +0.00011266336187471834 60575:60575 +0.00011266336187471834 57821:57821 +0.00011266336187471834 33043:33043 +0.00011266336187471834 34952:34952 +0.00011266336187471834 33750:33750 +0.00011266336187471834 57494:57494 +0.00011266336187471834 58613:58613 +0.00011266336187471834 56679:56679 +0.00011266336187471834 32964:32964 +0.00011266336187471834 56875:56875 +0.00011266336187471834 58042:58042 +0.00011266336187471834 57008:57008 +0.00011266336187471834 58115:58115 +0.00011266336187471834 57839:57839 +0.00011266336187471834 58790:58790 +0.00011266336187471834 58862:58862 +0.00011266336187471834 33749:33749 +0.00011266336187471834 34743:34743 +0.00011266336187471834 56929:56929 +0.00011266336187471834 56900:56900 +0.00011266336187471834 34498:34498 +0.00011266336187471834 32812:32812 +0.00011266336187471834 56682:56682 +0.00011266336187471834 33345:33345 +0.00011266336187471834 57885:57885 +0.00011266336187471834 56326:56326 +0.00011266336187471834 58968:58968 +0.00011266336187471834 57535:57535 +0.00011266336187471834 60123:60123 +0.00011266336187471834 56610:56610 +0.00011266336187471834 35410:35410 +0.00011266336187471834 56487:56487 +0.00011266336187471834 55950:55950 +0.00011266336187471834 57034:57034 +0.00011266336187471834 32900:32900 +0.00011266336187471834 35399:35399 +0.00011266336187471834 55673:55673 +0.00011266336187471834 57500:57500 +0.00011266336187471834 56292:56292 +0.00011266336187471834 59848:59848 +0.00011266336187471834 60190:60190 +0.00011266336187471834 57404:57404 +0.00011266336187471834 33539:33539 +0.00011266336187471834 35326:35326 +0.00011266336187471834 59720:59720 +0.00011266336187471834 56293:56293 +0.00011266336187471834 57745:57745 +0.00011266336187471834 33287:33287 +0.00011266336187471834 33962:33962 +0.00011266336187471834 33769:33769 +0.00011266336187471834 59335:59335 +0.00011266336187471834 33305:33305 +0.00011266336187471834 57259:57259 +0.00011266336187471834 35480:35480 +0.00011266336187471834 57898:57898 +0.00011266336187471834 58919:58919 +0.00011266336187471834 57709:57709 +0.00011266336187471834 34836:34836 +0.00011266336187471834 58553:58553 +0.00011266336187471834 56160:56160 +0.00011266336187471834 34654:34654 +0.00011266336187471834 34516:34516 +0.00011266336187471834 33562:33562 +0.00011266336187471834 57537:57537 +0.00011266336187471834 56470:56470 +0.00011266336187471834 33975:33975 +0.00011266336187471834 58482:58482 +0.00011266336187471834 56498:56498 +0.00011266336187471834 33594:33594 +0.00011266336187471834 55616:55616 +0.00011266336187471834 35468:35468 +0.00011266336187471834 59636:59636 +0.00011266336187471834 59130:59130 +0.00011266336187471834 58929:58929 +0.00011266336187471834 58357:58357 +0.00011266336187471834 58748:58748 +0.00011266336187471834 56926:56926 +0.00011266336187471834 60279:60279 +0.00011266336187471834 57682:57682 +0.00011266336187471834 33054:33054 +0.00011266336187471834 57867:57867 +0.00011266336187471834 35056:35056 +0.00011266336187471834 59343:59343 +0.00011266336187471834 58039:58039 +0.00011266336187471834 34416:34416 +0.00011266336187471834 33775:33775 +0.00011266336187471834 58713:58713 +0.00011266336187471834 56502:56502 +0.00011266336187471834 59914:59914 +0.00011266336187471834 34173:34173 +0.00011266336187471834 60640:60640 +0.00011266336187471834 57269:57269 +0.00011266336187471834 59291:59291 +0.00011266336187471834 60494:60494 +0.00011266336187471834 58058:58058 +0.00011266336187471834 60033:60033 +0.00011266336187471834 34384:34384 +0.00011266336187471834 56275:56275 +0.00011266336187471834 60530:60530 +0.00011266336187471834 35031:35031 +0.00011266336187471834 32976:32976 +0.00011266336187471834 55778:55778 +0.00011266336187471834 59863:59863 +0.00011266336187471834 57741:57741 +0.00011266336187471834 55684:55684 +0.00011266336187471834 60489:60489 +0.00011266336187471834 34205:34205 +0.00011266336187471834 33581:33581 +0.00011266336187471834 57742:57742 +0.00011266336187471834 58481:58481 +0.00011266336187471834 59469:59469 +0.00011266336187471834 35396:35396 +0.00011266336187471834 59774:59774 +0.00011266336187471834 34931:34931 +0.00011266336187471834 57308:57308 +0.00011266336187471834 35288:35288 +0.00011266336187471834 35044:35044 +0.00011266336187471834 58282:58282 +0.00011266336187471834 56503:56503 +0.00011266336187471834 57017:57017 +0.00011266336187471834 57604:57604 +0.00011266336187471834 35102:35102 +0.00011266336187471834 34028:34028 +0.00011266336187471834 60928:60928 +0.00011266336187471834 59647:59647 +0.00011266336187471834 33263:33263 +0.00011266336187471834 33169:33169 +0.00011266336187471834 58575:58575 +0.00011266336187471834 56664:56664 +0.00011266336187471834 60160:60160 +0.00011266336187471834 56102:56102 +0.00011266336187471834 33566:33566 +0.00011266336187471834 33327:33327 +0.00011266336187471834 60910:60910 +0.00011266336187471834 34017:34017 +0.00011266336187471834 34807:34807 +0.00011266336187471834 35049:35049 +0.00011266336187471834 60619:60619 +0.00011266336187471834 58194:58194 +0.00011266336187471834 59533:59533 +0.00011266336187471834 34074:34074 +0.00011266336187471834 58602:58602 +0.00011266336187471834 58079:58079 +0.00011266336187471834 57700:57700 +0.00011266336187471834 35314:35314 +0.00011266336187471834 60430:60430 +0.00011266336187471834 33862:33862 +0.00011266336187471834 55911:55911 +0.00011266336187471834 33705:33705 +0.00011266336187471834 56300:56300 +0.00011266336187471834 57386:57386 +0.00011266336187471834 59873:59873 +0.00011266336187471834 55690:55690 +0.00011266336187471834 34096:34096 +0.00011266336187471834 32927:32927 +0.00011266336187471834 60566:60566 +0.00011266336187471834 34802:34802 +0.00011266336187471834 55822:55822 +0.00011266336187471834 58066:58066 +0.00011266336187471834 33671:33671 +0.00011266336187471834 35069:35069 +0.00011266336187471834 34228:34228 +0.00011266336187471834 32945:32945 +0.00011266336187471834 57348:57348 +0.00011266336187471834 34876:34876 +0.00011266336187471834 59273:59273 +0.00011266336187471834 34941:34941 +0.00011266336187471834 57795:57795 +0.00011266336187471834 57554:57554 +0.00011266336187471834 57490:57490 +0.00011266336187471834 60809:60809 +0.00011266336187471834 59924:59924 +0.00011266336187471834 34621:34621 +0.00011266336187471834 55766:55766 +0.00011266336187471834 33557:33557 +0.00011266336187471834 57685:57685 +0.00011266336187471834 60139:60139 +0.00011266336187471834 57434:57434 +0.00011266336187471834 58540:58540 +0.00011266336187471834 35402:35402 +0.00011266336187471834 34632:34632 +0.00011266336187471834 32962:32962 +0.00011266336187471834 60120:60120 +0.00011266336187471834 59826:59826 +0.00011266336187471834 55972:55972 +0.00011266336187471834 34913:34913 +0.00011266336187471834 59850:59850 +0.00011266336187471834 58377:58377 +0.00011266336187471834 57332:57332 +0.00011266336187471834 33760:33760 +0.00011266336187471834 56378:56378 +0.00011266336187471834 60890:60890 +0.00011266336187471834 57526:57526 +0.00011266336187471834 35356:35356 +0.00011266336187471834 33262:33262 +0.00011266336187471834 34528:34528 +0.00011266336187471834 34480:34480 +0.00011266336187471834 55884:55884 +0.00011266336187471834 35352:35352 +0.00011266336187471834 58428:58428 +0.00011266336187471834 60480:60480 +0.00011266336187471834 35313:35313 +0.00011266336187471834 34367:34367 +0.00011266336187471834 56880:56880 +0.00011266336187471834 59323:59323 +0.00011266336187471834 59131:59131 +0.00011266336187471834 58472:58472 +0.00011266336187471834 34440:34440 +0.00011266336187471834 34975:34975 +0.00011266336187471834 57895:57895 +0.00011266336187471834 57147:57147 +0.00011266336187471834 57061:57061 +0.00011266336187471834 58360:58360 +0.00011266336187471834 58082:58082 +0.00011266336187471834 59915:59915 +0.00011266336187471834 59067:59067 +0.00011266336187471834 35558:35558 +0.00011266336187471834 59499:59499 +0.00011266336187471834 57345:57345 +0.00011266336187471834 56391:56391 +0.00011266336187471834 55627:55627 +0.00011266336187471834 35373:35373 +0.00011266336187471834 59545:59545 +0.00011266336187471834 55938:55938 +0.00011266336187471834 58767:58767 +0.00011266336187471834 34630:34630 +0.00011266336187471834 56468:56468 +0.00011266336187471834 56781:56781 +0.00011266336187471834 33320:33320 +0.00011266336187471834 34504:34504 +0.00011266336187471834 59918:59918 +0.00011266336187471834 57620:57620 +0.00011266336187471834 34767:34767 +0.00011266336187471834 58976:58976 +0.00011266336187471834 58054:58054 +0.00011266336187471834 56345:56345 +0.00011266336187471834 60723:60723 +0.00011266336187471834 60688:60688 +0.00011266336187471834 59428:59428 +0.00011266336187471834 56100:56100 +0.00011266336187471834 55967:55967 +0.00011266336187471834 56546:56546 +0.00011266336187471834 34726:34726 +0.00011266336187471834 33446:33446 +0.00011266336187471834 58583:58583 +0.00011266336187471834 59986:59986 +0.00011266336187471834 34896:34896 +0.00011266336187471834 58519:58519 +0.00011266336187471834 55901:55901 +0.00011266336187471834 60026:60026 +0.00011266336187471834 32897:32897 +0.00011266336187471834 56206:56206 +0.00011266336187471834 58915:58915 +0.00011266336187471834 34198:34198 +0.00011266336187471834 57847:57847 +0.00011266336187471834 57947:57947 +0.00011266336187471834 60101:60101 +0.00011266336187471834 57096:57096 +0.00011266336187471834 35448:35448 +0.00011266336187471834 56617:56617 +0.00011266336187471834 34176:34176 +0.00011266336187471834 60179:60179 +0.00011266336187471834 60519:60519 +0.00011266336187471834 33470:33470 +0.00011266336187471834 60037:60037 +0.00011266336187471834 34887:34887 +0.00011266336187471834 58002:58002 +0.00011266336187471834 33677:33677 +0.00011266336187471834 58499:58499 +0.00011266336187471834 57244:57244 +0.00011266336187471834 33852:33852 +0.00011266336187471834 33415:33415 +0.00011266336187471834 33152:33152 +0.00011266336187471834 56586:56586 +0.00011266336187471834 60297:60297 +0.00011266336187471834 56521:56521 +0.00011266336187471834 59549:59549 +0.00011266336187471834 35362:35362 +0.00011266336187471834 34865:34865 +0.00011266336187471834 34609:34609 +0.00011266336187471834 58397:58397 +0.00011266336187471834 57124:57124 +0.00011266336187471834 56273:56273 +0.00011266336187471834 35441:35441 +0.00011266336187471834 34003:34003 +0.00011266336187471834 33547:33547 +0.00011266336187471834 60984:60984 +0.00011266336187471834 60692:60692 +0.00011266336187471834 58361:58361 +0.00011266336187471834 57282:57282 +0.00011266336187471834 33817:33817 +0.00011266336187471834 33114:33114 +0.00011266336187471834 56186:56186 +0.00011266336187471834 56428:56428 +0.00011266336187471834 33819:33819 +0.00011266336187471834 55859:55859 +0.00011266336187471834 59167:59167 +0.00011266336187471834 59021:59021 +0.00011266336187471834 57863:57863 +0.00011266336187471834 60641:60641 +0.00011266336187471834 60170:60170 +0.00011266336187471834 58291:58291 +0.00011266336187471834 55939:55939 +0.00011266336187471834 34064:34064 +0.00011266336187471834 60124:60124 +0.00011266336187471834 33485:33485 +0.00011266336187471834 59823:59823 +0.00011266336187471834 33181:33181 +0.00011266336187471834 32981:32981 +0.00011266336187471834 56908:56908 +0.00011266336187471834 56039:56039 +0.00011266336187471834 55825:55825 +0.00011266336187471834 35099:35099 +0.00011266336187471834 33973:33973 +0.00011266336187471834 33370:33370 +0.00011266336187471834 32894:32894 +0.00011266336187471834 33471:33471 +0.00011266336187471834 33423:33423 +0.00011266336187471834 57150:57150 +0.00011266336187471834 32819:32819 +0.00011266336187471834 57249:57249 +0.00011266336187471834 60458:60458 +0.00011266336187471834 59054:59054 +0.00011266336187471834 57285:57285 +0.00011266336187471834 35003:35003 +0.00011266336187471834 33215:33215 +0.00011266336187471834 57632:57632 +0.00011266336187471834 57298:57298 +0.00011266336187471834 60931:60931 +0.00011266336187471834 58392:58392 +0.00011266336187471834 57985:57985 +0.00011266336187471834 58201:58201 +0.00011266336187471834 56375:56375 +0.00011266336187471834 58134:58134 +0.00011266336187471834 58264:58264 +0.00011266336187471834 57792:57792 +0.00011266336187471834 35262:35262 +0.00011266336187471834 33847:33847 +0.00011266336187471834 59963:59963 +0.00011266336187471834 56904:56904 +0.00011266336187471834 60585:60585 +0.00011266336187471834 60105:60105 +0.00011266336187471834 33017:33017 +0.00011266336187471834 59792:59792 +0.00011266336187471834 58680:58680 +0.00011266336187471834 35401:35401 +0.00011266336187471834 60282:60282 +0.00011266336187471834 58048:58048 +0.00011266336187471834 34201:34201 +0.00011266336187471834 60456:60456 +0.00011266336187471834 34322:34322 +0.00011266336187471834 33701:33701 +0.00011266336187471834 59463:59463 +0.00011266336187471834 33610:33610 +0.00011266336187471834 58611:58611 +0.00011266336187471834 56448:56448 +0.00011266336187471834 58149:58149 +0.00011266336187471834 58049:58049 +0.00011266336187471834 58928:58928 +0.00011266336187471834 34744:34744 +0.00011266336187471834 60768:60768 +0.00011266336187471834 56850:56850 +0.00011266336187471834 56634:56634 +0.00011266336187471834 59804:59804 +0.00011266336187471834 34219:34219 +0.00011266336187471834 60513:60513 +0.00011266336187471834 59656:59656 +0.00011266336187471834 56348:56348 +0.00011266336187471834 55760:55760 +0.00011266336187471834 58841:58841 +0.00011266336187471834 60727:60727 +0.00011266336187471834 60291:60291 +0.00011266336187471834 59376:59376 +0.00011266336187471834 59207:59207 +0.00011266336187471834 35230:35230 +0.00011266336187471834 33832:33832 +0.00011266336187471834 33818:33818 +0.00011266336187471834 56636:56636 +0.00011266336187471834 56327:56327 +0.00011266336187471834 55927:55927 +0.00011266336187471834 34772:34772 +0.00011266336187471834 34161:34161 +0.00011266336187471834 32893:32893 +0.00011266336187471834 55919:55919 +0.00011266336187471834 34946:34946 +0.00011266336187471834 33350:33350 +0.00011266336187471834 56236:56236 +0.00011266336187471834 34794:34794 +0.00011266336187471834 33584:33584 +0.00011266336187471834 61000:61000 +0.00011266336187471834 60422:60422 +0.00011266336187471834 60522:60522 +0.00011266336187471834 33989:33989 +0.00011266336187471834 33042:33042 +0.00011266336187471834 59421:59421 +0.00011266336187471834 60208:60208 +0.00011266336187471834 34364:34364 +0.00011266336187471834 59583:59583 +0.00011266336187471834 57133:57133 +0.00011266336187471834 35078:35078 +0.00011266336187471834 59770:59770 +0.00011266336187471834 58582:58582 +0.00011266336187471834 33667:33667 +0.00011266336187471834 33332:33332 +0.00011266336187471834 57890:57890 +0.00011266336187471834 59445:59445 +0.00011266336187471834 58909:58909 +0.00011266336187471834 58510:58510 +0.00011266336187471834 35082:35082 +0.00011266336187471834 34244:34244 +0.00011266336187471834 58935:58935 +0.00011266336187471834 34264:34264 +0.00011266336187471834 33223:33223 +0.00011266336187471834 56828:56828 +0.00011266336187471834 58528:58528 +0.00011266336187471834 57716:57716 +0.00011266336187471834 57428:57428 +0.00011266336187471834 35063:35063 +0.00011266336187471834 59118:59118 +0.00011266336187471834 56673:56673 +0.00011266336187471834 55707:55707 +0.00011266336187471834 60846:60846 +0.00011266336187471834 58083:58083 +0.00011266336187471834 56595:56595 +0.00011266336187471834 58879:58879 +0.00011266336187471834 58549:58549 +0.00011266336187471834 35162:35162 +0.00011266336187471834 57894:57894 +0.00011266336187471834 57881:57881 +0.00011266336187471834 60314:60314 +0.00011266336187471834 60576:60576 +0.00011266336187471834 58502:58502 +0.00011266336187471834 58110:58110 +0.00011266336187471834 57053:57053 +0.00011266336187471834 56554:56554 +0.00011266336187471834 60634:60634 +0.00011266336187471834 32907:32907 +0.00011266336187471834 57161:57161 +0.00011266336187471834 56523:56523 +0.00011266336187471834 35234:35234 +0.00011266336187471834 33883:33883 +0.00011266336187471834 58276:58276 +0.00011266336187471834 60823:60823 +0.00011266336187471834 55708:55708 +0.00011266336187471834 34420:34420 +0.00011266336187471834 57813:57813 +0.00011266336187471834 57692:57692 +0.00011266336187471834 58287:58287 +0.00011266336187471834 56121:56121 +0.00011266336187471834 33279:33279 +0.00011266336187471834 59788:59788 +0.00011266336187471834 33774:33774 +0.00011266336187471834 57103:57103 +0.00011266336187471834 56313:56313 +0.00011266336187471834 34423:34423 +0.00011266336187471834 33894:33894 +0.00011266336187471834 34607:34607 +0.00011266336187471834 33161:33161 +0.00011266336187471834 33166:33166 +0.00011266336187471834 59175:59175 +0.00011266336187471834 34575:34575 +0.00011266336187471834 60002:60002 +0.00011266336187471834 34577:34577 +0.00011266336187471834 56483:56483 +0.00011266336187471834 33710:33710 +0.00011266336187471834 33137:33137 +0.00011266336187471834 55667:55667 +0.00011266336187471834 58106:58106 +0.00011266336187471834 56358:56358 +0.00011266336187471834 35253:35253 +0.00011266336187471834 59172:59172 +0.00011266336187471834 56446:56446 +0.00011266336187471834 34050:34050 +0.00011266336187471834 60273:60273 +0.00011266336187471834 34588:34588 +0.00011266336187471834 34490:34490 +0.00011266336187471834 60486:60486 +0.00011266336187471834 58872:58872 +0.00011266336187471834 58188:58188 +0.00011266336187471834 35456:35456 +0.00011266336187471834 33455:33455 +0.00011266336187471834 58657:58657 +0.00011266336187471834 60339:60339 +0.00011266336187471834 56957:56957 +0.00011266336187471834 58470:58470 +0.00011266336187471834 59055:59055 +0.00011266336187471834 34542:34542 +0.00011266336187471834 60867:60867 +0.00011266336187471834 59635:59635 +0.00011266336187471834 33365:33365 +0.00011266336187471834 34669:34669 +0.00011266336187471834 33359:33359 +0.00011266336187471834 56233:56233 +0.00011266336187471834 58744:58744 +0.00011266336187471834 33777:33777 +0.00011266336187471834 60888:60888 +0.00011266336187471834 35165:35165 +0.00011266336187471834 60729:60729 +0.00011266336187471834 56315:56315 +0.00011266336187471834 58372:58372 +0.00011266336187471834 57751:57751 +0.00011266336187471834 60238:60238 +0.00011266336187471834 55985:55985 +0.00011266336187471834 32858:32858 +0.00011266336187471834 34773:34773 +0.00011266336187471834 34993:34993 +0.00011266336187471834 60193:60193 +0.00011266336187471834 59474:59474 +0.00011266336187471834 34521:34521 +0.00011266336187471834 55991:55991 +0.00011266336187471834 35344:35344 +0.00011266336187471834 56714:56714 +0.00011266336187471834 33811:33811 +0.00011266336187471834 33280:33280 +0.00011266336187471834 34090:34090 +0.00011266336187471834 33510:33510 +0.00011266336187471834 34482:34482 +0.00011266336187471834 60934:60934 +0.00011266336187471834 34809:34809 +0.00011266336187471834 34549:34549 +0.00011266336187471834 56766:56766 +0.00011266336187471834 60916:60916 +0.00011266336187471834 55829:55829 +0.00011266336187471834 60431:60431 +0.00011266336187471834 56853:56853 +0.00011266336187471834 60673:60673 +0.00011266336187471834 34838:34838 +0.00011266336187471834 55687:55687 +0.00011266336187471834 35158:35158 +0.00011266336187471834 58717:58717 +0.00011266336187471834 60638:60638 +0.00011266336187471834 60473:60473 +0.00011266336187471834 33478:33478 +0.00011266336187471834 60821:60821 +0.00011266336187471834 34447:34447 +0.00011266336187471834 57580:57580 +0.00011266336187471834 60056:60056 +0.00011266336187471834 60626:60626 +0.00011266336187471834 56471:56471 +0.00011266336187471834 34518:34518 +0.00011266336187471834 34133:34133 +0.00011266336187471834 33386:33386 +0.00011266336187471834 56006:56006 +0.00011266336187471834 33527:33527 +0.00011266336187471834 33122:33122 +0.00011266336187471834 59407:59407 +0.00011266336187471834 34132:34132 +0.00011266336187471834 57822:57822 +0.00011266336187471834 33203:33203 +0.00011266336187471834 34476:34476 +0.00011266336187471834 33070:33070 +0.00011266336187471834 60740:60740 +0.00011266336187471834 59108:59108 +0.00011266336187471834 58525:58525 +0.00011266336187471834 56103:56103 +0.00011266336187471834 34639:34639 +0.00011266336187471834 34459:34459 +0.00011266336187471834 59837:59837 +0.00011266336187471834 56605:56605 +0.00011266336187471834 56489:56489 +0.00011266336187471834 58726:58726 +0.00011266336187471834 57702:57702 +0.00011266336187471834 34496:34496 +0.00011266336187471834 57287:57287 +0.00011266336187471834 34065:34065 +0.00011266336187471834 34032:34032 +0.00011266336187471834 58364:58364 +0.00011266336187471834 59775:59775 +0.00011266336187471834 58187:58187 +0.00011266336187471834 57518:57518 +0.00011266336187471834 55925:55925 +0.00011266336187471834 56988:56988 +0.00011266336187471834 59211:59211 +0.00011266336187471834 57397:57397 +0.00011266336187471834 59354:59354 +0.00011266336187471834 35447:35447 +0.00011266336187471834 59168:59168 +0.00011266336187471834 58610:58610 +0.00011266336187471834 34307:34307 +0.00011266336187471834 58089:58089 +0.00011266336187471834 60225:60225 +0.00011266336187471834 57931:57931 +0.00011266336187471834 56893:56893 +0.00011266336187471834 58301:58301 +0.00011266336187471834 32787:32787 +0.00011266336187471834 59951:59951 +0.00011266336187471834 55981:55981 +0.00011266336187471834 59337:59337 +0.00011266336187471834 59006:59006 +0.00011266336187471834 58505:58505 +0.00011266336187471834 35127:35127 +0.00011266336187471834 56066:56066 +0.00011266336187471834 35252:35252 +0.00011266336187471834 59002:59002 +0.00011266336187471834 57609:57609 +0.00011266336187471834 35129:35129 +0.00011266336187471834 34595:34595 +0.00011266336187471834 33924:33924 +0.00011266336187471834 60446:60446 +0.00011266336187471834 35210:35210 +0.00011266336187471834 55648:55648 +0.00011266336187471834 57677:57677 +0.00011266336187471834 57010:57010 +0.00011266336187471834 35231:35231 +0.00011266336187471834 59181:59181 +0.00011266336187471834 57316:57316 +0.00011266336187471834 60369:60369 +0.00011266336187471834 33356:33356 +0.00011266336187471834 33111:33111 +0.00011266336187471834 35073:35073 +0.00011266336187471834 34088:34088 +0.00011266336187471834 60750:60750 +0.00011266336187471834 58695:58695 +0.00011266336187471834 57790:57790 +0.00011266336187471834 56200:56200 +0.00011266336187471834 33417:33417 +0.00011266336187471834 57874:57874 +0.00011266336187471834 56266:56266 +0.00011266336187471834 33612:33612 +0.00011266336187471834 57432:57432 +0.00011266336187471834 56855:56855 +0.00011266336187471834 60181:60181 +0.00011266336187471834 56154:56154 +0.00011266336187471834 60290:60290 +0.00011266336187471834 56611:56611 +0.00011266336187471834 58807:58807 +0.00011266336187471834 56311:56311 +0.00011266336187471834 56457:56457 +0.00011266336187471834 55863:55863 +0.00011266336187471834 57436:57436 +0.00011266336187471834 33869:33869 +0.00011266336187471834 34084:34084 +0.00011266336187471834 57990:57990 +0.00011266336187471834 56009:56009 +0.00011266336187471834 60941:60941 +0.00011266336187471834 60837:60837 +0.00011266336187471834 34033:34033 +0.00011266336187471834 57164:57164 +0.00011266336187471834 55880:55880 +0.00011266336187471834 60778:60778 +0.00011266336187471834 59760:59760 +0.00011266336187471834 59556:59556 +0.00011266336187471834 60694:60694 +0.00011266336187471834 33227:33227 +0.00011266336187471834 60994:60994 +0.00011266336187471834 35085:35085 +0.00011266336187471834 58410:58410 +0.00011266336187471834 60889:60889 +0.00011266336187471834 57163:57163 +0.00011266336187471834 58380:58380 +0.00011266336187471834 56045:56045 +0.00011266336187471834 59780:59780 +0.00011266336187471834 57773:57773 +0.00011266336187471834 33031:33031 +0.00011266336187471834 59851:59851 +0.00011266336187471834 59274:59274 +0.00011266336187471834 59287:59287 +0.00011266336187471834 55837:55837 +0.00011266336187471834 60210:60210 +0.00011266336187471834 60687:60687 +0.00011266336187471834 57949:57949 +0.00011266336187471834 60534:60534 +0.00011266336187471834 33367:33367 +0.00011266336187471834 58868:58868 +0.00011266336187471834 35100:35100 +0.00011266336187471834 60798:60798 +0.00011266336187471834 55879:55879 +0.00011266336187471834 33599:33599 +0.00011266336187471834 34049:34049 +0.00011266336187471834 34660:34660 +0.00011266336187471834 59240:59240 +0.00011266336187471834 34559:34559 +0.00011266336187471834 33799:33799 +0.00011266336187471834 58130:58130 +0.00011266336187471834 57472:57472 +0.00011266336187471834 32825:32825 +0.00011266336187471834 34955:34955 +0.00011266336187471834 60524:60524 +0.00011266336187471834 57703:57703 +0.00011266336187471834 33216:33216 +0.00011266336187471834 60842:60842 +0.00011266336187471834 59968:59968 +0.00011266336187471834 35502:35502 +0.00011266336187471834 58062:58062 +0.00011266336187471834 34076:34076 +0.00011266336187471834 59685:59685 +0.00011266336187471834 56678:56678 +0.00011266336187471834 34026:34026 +0.00011266336187471834 57835:57835 +0.00011266336187471834 56153:56153 +0.00011266336187471834 56951:56951 +0.00011266336187471834 58771:58771 +0.00011266336187471834 57764:57764 +0.00011266336187471834 33473:33473 +0.00011266336187471834 59557:59557 +0.00011266336187471834 57514:57514 +0.00011266336187471834 34878:34878 +0.00011266336187471834 34098:34098 +0.00011266336187471834 33348:33348 +0.00011266336187471834 60593:60593 +0.00011266336187471834 35135:35135 +0.00011266336187471834 59137:59137 +0.00011266336187471834 56026:56026 +0.00011266336187471834 35296:35296 +0.00011266336187471834 56817:56817 +0.00011266336187471834 33404:33404 +0.00011266336187471834 34167:34167 +0.00011266336187471834 33018:33018 +0.00011266336187471834 57679:57679 +0.00011266336187471834 57601:57601 +0.00011266336187471834 35297:35297 +0.00011266336187471834 59581:59581 +0.00011266336187471834 59212:59212 +0.00011266336187471834 59094:59094 +0.00011266336187471834 57530:57530 +0.00011266336187471834 56897:56897 +0.00011266336187471834 35349:35349 +0.00011266336187471834 59662:59662 +0.00011266336187471834 58097:58097 +0.00011266336187471834 57635:57635 +0.00011266336187471834 60404:60404 +0.00011266336187471834 59740:59740 +0.00011266336187471834 35118:35118 +0.00011266336187471834 34047:34047 +0.00011266336187471834 33996:33996 +0.00011266336187471834 35552:35552 +0.00011266336187471834 35164:35164 +0.00011266336187471834 56681:56681 +0.00011266336187471834 59043:59043 +0.00011266336187471834 57592:57592 +0.00011266336187471834 57347:57347 +0.00011266336187471834 35439:35439 +0.00011266336187471834 33736:33736 +0.00011266336187471834 58414:58414 +0.00011266336187471834 34310:34310 +0.00011266336187471834 56740:56740 +0.00011266336187471834 34914:34914 +0.00011266336187471834 57905:57905 +0.00011266336187471834 55897:55897 +0.00011266336187471834 33275:33275 +0.00011266336187471834 33063:33063 +0.00011266336187471834 59992:59992 +0.00011266336187471834 56878:56878 +0.00011266336187471834 56167:56167 +0.00011266336187471834 60427:60427 +0.00011266336187471834 58236:58236 +0.00011266336187471834 58065:58065 +0.00011266336187471834 33237:33237 +0.00011266336187471834 59572:59572 +0.00011266336187471834 33966:33966 +0.00011266336187471834 58901:58901 +0.00011266336187471834 55772:55772 +0.00011266336187471834 34093:34093 +0.00011266336187471834 60500:60500 +0.00011266336187471834 58805:58805 +0.00011266336187471834 58337:58337 +0.00011266336187471834 33021:33021 +0.00011266336187471834 58109:58109 +0.00011266336187471834 56860:56860 +0.00011266336187471834 60154:60154 +0.00011266336187471834 58997:58997 +0.00011266336187471834 60860:60860 +0.00011266336187471834 60042:60042 +0.00011266336187471834 56552:56552 +0.00011266336187471834 34973:34973 +0.00011266336187471834 56972:56972 +0.00011266336187471834 56826:56826 +0.00011266336187471834 55871:55871 +0.00011266336187471834 33329:33329 +0.00011266336187471834 58541:58541 +0.00011266336187471834 57782:57782 +0.00011266336187471834 33138:33138 +0.00011266336187471834 57382:57382 +0.00011266336187471834 33147:33147 +0.00011266336187471834 58240:58240 +0.00011266336187471834 34334:34334 +0.00011266336187471834 55723:55723 +0.00011266336187471834 56743:56743 +0.00011266336187471834 57902:57902 +0.00011266336187471834 59877:59877 +0.00011266336187471834 34200:34200 +0.00011266336187471834 32821:32821 +0.00011266336187471834 60092:60092 +0.00011266336187471834 59275:59275 +0.00011266336187471834 57648:57648 +0.00011266336187471834 60780:60780 +0.00011266336187471834 33292:33292 +0.00011266336187471834 59949:59949 +0.00011266336187471834 57388:57388 +0.00011266336187471834 58033:58033 +0.00011266336187471834 55705:55705 +0.00011266336187471834 34923:34923 +0.00011266336187471834 60413:60413 +0.00011266336187471834 56824:56824 +0.00011266336187471834 33125:33125 +0.00011266336187471834 59825:59825 +0.00011266336187471834 57406:57406 +0.00011266336187471834 56230:56230 +0.00011266336187471834 60294:60294 +0.00011266336187471834 57152:57152 +0.00011266336187471834 32775:32775 +0.00011266336187471834 58539:58539 +0.00011266336187471834 33871:33871 +0.00011266336187471834 56255:56255 +0.00011266336187471834 60756:60756 +0.00011266336187471834 34039:34039 +0.00011266336187471834 32839:32839 +0.00011266336187471834 60504:60504 +0.00011266336187471834 58538:58538 +0.00011266336187471834 56058:56058 +0.00011266336187471834 33627:33627 +0.00011266336187471834 34053:34053 +0.00011266336187471834 58196:58196 +0.00011266336187471834 58027:58027 +0.00011266336187471834 60999:60999 +0.00011266336187471834 34350:34350 +0.00011266336187471834 32769:32769 +0.00011266336187471834 59937:59937 +0.00011266336187471834 55817:55817 +0.00011266336187471834 55757:55757 +0.00011266336187471834 60840:60840 +0.00011266336187471834 35359:35359 +0.00011266336187471834 58569:58569 +0.00011266336187471834 58552:58552 +0.00011266336187471834 57525:57525 +0.00011266336187471834 33221:33221 +0.00011266336187471834 59150:59150 +0.00011266336187471834 59828:59828 +0.00011266336187471834 33086:33086 +0.00011266336187471834 34573:34573 +0.00011266336187471834 60013:60013 +0.00011266336187471834 56984:56984 +0.00011266336187471834 33602:33602 +0.00011266336187471834 59536:59536 +0.00011266336187471834 32803:32803 +0.00011266336187471834 56980:56980 +0.00011266336187471834 34760:34760 +0.00011266336187471834 58167:58167 +0.00011266336187471834 59993:59993 +0.00011266336187471834 56271:56271 +0.00011266336187471834 33887:33887 +0.00011266336187471834 60089:60089 +0.00011266336187471834 57023:57023 +0.00011266336187471834 56060:56060 +0.00011266336187471834 57661:57661 +0.00011266336187471834 33851:33851 +0.00011266336187471834 58743:58743 +0.00011266336187471834 33053:33053 +0.00011266336187471834 32906:32906 +0.00011266336187471834 60826:60826 +0.00011266336187471834 34508:34508 +0.00011266336187471834 59301:59301 +0.00011266336187471834 34315:34315 +0.00011266336187471834 60309:60309 +0.00011266336187471834 35435:35435 +0.00011266336187471834 58945:58945 +0.00011266336187471834 56426:56426 +0.00011266336187471834 33639:33639 +0.00011266336187471834 60590:60590 +0.00011266336187471834 57724:57724 +0.00011266336187471834 56947:56947 +0.00011266336187471834 60078:60078 +0.00011266336187471834 59899:59899 +0.00011266336187471834 59754:59754 +0.00011266336187471834 56464:56464 +0.00011266336187471834 33625:33625 +0.00011266336187471834 34443:34443 +0.00011266336187471834 34992:34992 +0.00011266336187471834 33737:33737 +0.00011266336187471834 34324:34324 +0.00011266336187471834 57880:57880 +0.00011266336187471834 56280:56280 +0.00011266336187471834 55960:55960 +0.00011266336187471834 32862:32862 +0.00011266336187471834 55738:55738 +0.00011266336187471834 34475:34475 +0.00011266336187471834 34280:34280 +0.00011266336187471834 56506:56506 +0.00011266336187471834 59690:59690 +0.00011266336187471834 57266:57266 +0.00011266336187471834 58630:58630 +0.00011266336187471834 35024:35024 +0.00011266336187471834 57208:57208 +0.00011266336187471834 34616:34616 +0.00011266336187471834 60368:60368 +0.00011266336187471834 59314:59314 +0.00011266336187471834 60259:60259 +0.00011266336187471834 60901:60901 +0.00011266336187471834 60055:60055 +0.00011266336187471834 34531:34531 +0.00011266336187471834 59763:59763 +0.00011266336187471834 58836:58836 +0.00011266336187471834 33328:33328 +0.00011266336187471834 60115:60115 +0.00011266336187471834 57489:57489 +0.00011266336187471834 57315:57315 +0.00011266336187471834 55861:55861 +0.00011266336187471834 59214:59214 +0.00011266336187471834 56212:56212 +0.00011266336187471834 35001:35001 +0.00011266336187471834 59521:59521 +0.00011266336187471834 57605:57605 +0.00011266336187471834 57349:57349 +0.00011266336187471834 60515:60515 +0.00011266336187471834 34110:34110 +0.00011266336187471834 60438:60438 +0.00011266336187471834 34217:34217 +0.00011266336187471834 60116:60116 +0.00011266336187471834 56710:56710 +0.00011266336187471834 56933:56933 +0.00011266336187471834 55691:55691 +0.00011266336187471834 58654:58654 +0.00011266336187471834 58445:58445 +0.00011266336187471834 56501:56501 +0.00011266336187471834 35312:35312 +0.00011266336187471834 58053:58053 +0.00011266336187471834 33509:33509 +0.00011266336187471834 34924:34924 +0.00011266336187471834 32924:32924 +0.00011266336187471834 60819:60819 +0.00011266336187471834 34383:34383 +0.00011266336187471834 35235:35235 +0.00011266336187471834 34015:34015 +0.00011266336187471834 35365:35365 +0.00011266336187471834 60685:60685 +0.00011266336187471834 59632:59632 +0.00011266336187471834 56193:56193 +0.00011266336187471834 59736:59736 +0.00011266336187471834 57688:57688 +0.00011266336187471834 34720:34720 +0.00011266336187471834 34136:34136 +0.00011266336187471834 60481:60481 +0.00011266336187471834 60268:60268 +0.00011266336187471834 57458:57458 +0.00011266336187471834 57757:57757 +0.00011266336187471834 59442:59442 +0.00011266336187471834 58443:58443 +0.00011266336187471834 34139:34139 +0.00011266336187471834 59794:59794 +0.00011266336187471834 56876:56876 +0.00011266336187471834 56747:56747 +0.00011266336187471834 60151:60151 +0.00011266336187471834 58125:58125 +0.00011266336187471834 34536:34536 +0.00011266336187471834 58772:58772 +0.00011266336187471834 56304:56304 +0.00011266336187471834 32942:32942 +0.00011266336187471834 58461:58461 +0.00011266336187471834 57986:57986 +0.00011266336187471834 60076:60076 +0.00011266336187471834 60788:60788 +0.00011266336187471834 56921:56921 +0.00011266336187471834 35226:35226 +0.00011266336187471834 57401:57401 +0.00011266336187471834 56606:56606 +0.00011266336187471834 35407:35407 +0.00011266336187471834 57267:57267 +0.00011266336187471834 58474:58474 +0.00011266336187471834 58422:58422 +0.00011266336187471834 56742:56742 +0.00011266336187471834 56639:56639 +0.00011266336187471834 56162:56162 +0.00011266336187471834 59039:59039 +0.00011266336187471834 57227:57227 +0.00011266336187471834 33587:33587 +0.00011266336187471834 32808:32808 +0.00011266336187471834 59517:59517 +0.00011266336187471834 59964:59964 +0.00011266336187471834 56661:56661 +0.00011266336187471834 56122:56122 +0.00011266336187471834 59135:59135 +0.00011266336187471834 33438:33438 +0.00011266336187471834 58175:58175 +0.00011266336187471834 59093:59093 +0.00011266336187471834 55750:55750 +0.00011266336187471834 60251:60251 +0.00011266336187471834 34585:34585 +0.00011266336187471834 59978:59978 +0.00011266336187471834 56831:56831 +0.00011266336187471834 60636:60636 +0.00011266336187471834 34502:34502 +0.00011266336187471834 34381:34381 +0.00011266336187471834 59261:59261 +0.00011266336187471834 57221:57221 +0.00011266336187471834 60138:60138 +0.00011266336187471834 32909:32909 +0.00011266336187471834 60221:60221 +0.00011266336187471834 56966:56966 +0.00011266336187471834 56495:56495 +0.00011266336187471834 60609:60609 +0.00011266336187471834 58638:58638 +0.00011266336187471834 55661:55661 +0.00011266336187471834 33911:33911 +0.00011266336187471834 60276:60276 +0.00011266336187471834 59904:59904 +0.00011266336187471834 56894:56894 +0.00011266336187471834 58465:58465 +0.00011266336187471834 55709:55709 +0.00011266336187471834 57224:57224 +0.00011266336187471834 60265:60265 +0.00011266336187471834 57392:57392 +0.00011266336187471834 35375:35375 +0.00011266336187471834 58265:58265 +0.00011266336187471834 57591:57591 +0.00011266336187471834 33097:33097 +0.00011266336187471834 60064:60064 +0.00011266336187471834 57777:57777 +0.00011266336187471834 57098:57098 +0.00011266336187471834 32923:32923 +0.00011266336187471834 58514:58514 +0.00011266336187471834 33582:33582 +0.00011266336187471834 56316:56316 +0.00011266336187471834 56314:56314 +0.00011266336187471834 33206:33206 +0.00011266336187471834 58786:58786 +0.00011266336187471834 35090:35090 +0.00011266336187471834 35015:35015 +0.00011266336187471834 59542:59542 +0.00011266336187471834 58031:58031 +0.00011266336187471834 34453:34453 +0.00011266336187471834 32975:32975 +0.00011266336187471834 57973:57973 +0.00011266336187471834 60965:60965 +0.00011266336187471834 60365:60365 +0.00011266336187471834 58485:58485 +0.00011266336187471834 57912:57912 +0.00011266336187471834 34306:34306 +0.00011266336187471834 33414:33414 +0.00011266336187471834 56783:56783 +0.00011266336187471834 33253:33253 +0.00011266336187471834 60143:60143 +0.00011266336187471834 35411:35411 +0.00011266336187471834 33266:33266 +0.00011266336187471834 60558:60558 +0.00011266336187471834 56971:56971 +0.00011266336187471834 34954:34954 +0.00011266336187471834 33310:33310 +0.00011266336187471834 35500:35500 +0.00011266336187471834 33302:33302 +0.00011266336187471834 57274:57274 +0.00011266336187471834 35239:35239 +0.00011266336187471834 60478:60478 +0.00011266336187471834 60025:60025 +0.00011266336187471834 33853:33853 +0.00011266336187471834 33607:33607 +0.00011266336187471834 58182:58182 +0.00011266336187471834 55647:55647 +0.00011266336187471834 34714:34714 +0.00011266336187471834 57988:57988 +0.00011266336187471834 56749:56749 +0.00011266336187471834 33297:33297 +0.00011266336187471834 58612:58612 +0.00011266336187471834 58172:58172 +0.00011266336187471834 55784:55784 +0.00011266336187471834 56582:56582 +0.00011266336187471834 34668:34668 +0.00011266336187471834 60215:60215 +0.00011266336187471834 57660:57660 +0.00011266336187471834 35249:35249 +0.00011266336187471834 35216:35216 +0.00011266336187471834 34214:34214 +0.00011266336187471834 57597:57597 +0.00011266336187471834 59086:59086 +0.00011266336187471834 56560:56560 +0.00011266336187471834 60023:60023 +0.00011266336187471834 34725:34725 +0.00011266336187471834 59260:59260 +0.00011266336187471834 33936:33936 +0.00011266336187471834 60625:60625 +0.00011266336187471834 56578:56578 +0.00011266336187471834 34112:34112 +0.00011266336187471834 34543:34543 +0.00011266336187471834 57576:57576 +0.00011266336187471834 56063:56063 +0.00011266336187471834 33229:33229 +0.00011266336187471834 58096:58096 +0.00011266336187471834 57823:57823 +0.00011266336187471834 56603:56603 +0.00011266336187471834 33219:33219 +0.00011266336187471834 60046:60046 +0.00011266336187471834 57786:57786 +0.00011266336187471834 58784:58784 +0.00011266336187471834 58387:58387 +0.00011266336187471834 59345:59345 +0.00011266336187471834 56753:56753 +0.00011266336187471834 59308:59308 +0.00011266336187471834 58702:58702 +0.00011266336187471834 57602:57602 +0.00011266336187471834 57886:57886 +0.00011266336187471834 33139:33139 +0.00011266336187471834 55756:55756 +0.00011266336187471834 60104:60104 +0.00011266336187471834 35153:35153 +0.00011266336187471834 60712:60712 +0.00011266336187471834 57109:57109 +0.00011266336187471834 60594:60594 +0.00011266336187471834 59155:59155 +0.00011266336187471834 55761:55761 +0.00011266336187471834 34442:34442 +0.00011266336187471834 60951:60951 +0.00011266336187471834 57527:57527 +0.00011266336187471834 60996:60996 +0.00011266336187471834 55660:55660 +0.00011266336187471834 34468:34468 +0.00011266336187471834 34101:34101 +0.00011266336187471834 35243:35243 +0.00011266336187471834 33444:33444 +0.00011266336187471834 58516:58516 +0.00011266336187471834 33131:33131 +0.00011266336187471834 34657:34657 +0.00011266336187471834 55995:55995 +0.00011266336187471834 56989:56989 +0.00011266336187471834 56672:56672 +0.00011266336187471834 55651:55651 +0.00011266336187471834 33401:33401 +0.00011266336187471834 33800:33800 +0.00011266336187471834 58248:58248 +0.00011266336187471834 56737:56737 +0.00011266336187471834 59339:59339 +0.00011266336187471834 57908:57908 +0.00011266336187471834 34680:34680 +0.00011266336187471834 60030:60030 +0.00011266336187471834 33377:33377 +0.00011266336187471834 32939:32939 +0.00011266336187471834 58789:58789 +0.00011266336187471834 56351:56351 +0.00011266336187471834 33293:33293 +0.00011266336187471834 35473:35473 +0.00011266336187471834 60546:60546 +0.00011266336187471834 58449:58449 +0.00011266336187471834 34291:34291 +0.00011266336187471834 58766:58766 +0.00011266336187471834 58477:58477 +0.00011266336187471834 60929:60929 +0.00011266336187471834 57111:57111 +0.00011266336187471834 34237:34237 +0.00011266336187471834 33726:33726 +0.00011266336187471834 35258:35258 +0.00011266336187471834 34544:34544 +0.00011266336187471834 33382:33382 +0.00011266336187471834 57372:57372 +0.00011266336187471834 56844:56844 +0.00011266336187471834 57054:57054 +0.00011266336187471834 56768:56768 +0.00011266336187471834 56369:56369 +0.00011266336187471834 55746:55746 +0.00011266336187471834 60591:60591 +0.00011266336187471834 59726:59726 +0.00011266336187471834 34349:34349 +0.00011266336187471834 55889:55889 +0.00011266336187471834 60539:60539 +0.00011266336187471834 55700:55700 +0.00011266336187471834 35133:35133 +0.00011266336187471834 35035:35035 +0.00011266336187471834 58662:58662 +0.00011266336187471834 57342:57342 +0.00011266336187471834 33431:33431 +0.00011266336187471834 32810:32810 +0.00011266336187471834 58253:58253 +0.00011266336187471834 60155:60155 +0.00011266336187471834 59748:59748 +0.00011266336187471834 57110:57110 +0.00011266336187471834 56267:56267 +0.00011266336187471834 58401:58401 +0.00011266336187471834 60004:60004 +0.00011266336187471834 34859:34859 +0.00011266336187471834 59801:59801 +0.00011266336187471834 35337:35337 +0.00011266336187471834 58497:58497 +0.00011266336187471834 57512:57512 +0.00011266336187471834 57846:57846 +0.00011266336187471834 58161:58161 +0.00011266336187471834 56449:56449 +0.00011266336187471834 33752:33752 +0.00011266336187471834 56309:56309 +0.00011266336187471834 35282:35282 +0.00011266336187471834 58037:58037 +0.00011266336187471834 34526:34526 +0.00011266336187471834 33256:33256 +0.00011266336187471834 57120:57120 +0.00011266336187471834 58524:58524 +0.00011266336187471834 58306:58306 +0.00011266336187471834 60087:60087 +0.00011266336187471834 58504:58504 +0.00011266336187471834 60172:60172 +0.00011266336187471834 33979:33979 +0.00011266336187471834 57608:57608 +0.00011266336187471834 57799:57799 +0.00011266336187471834 57177:57177 +0.00011266336187471834 56342:56342 +0.00011266336187471834 34213:34213 +0.00011266336187471834 59237:59237 +0.00011266336187471834 60644:60644 +0.00011266336187471834 56642:56642 +0.00011266336187471834 59707:59707 +0.00011266336187471834 56647:56647 +0.00011266336187471834 33155:33155 +0.00011266336187471834 34311:34311 +0.00011266336187471834 34511:34511 +0.00011266336187471834 33069:33069 +0.00011266336187471834 59420:59420 +0.00011266336187471834 55932:55932 +0.00011266336187471834 35248:35248 +0.00011266336187471834 34159:34159 +0.00011266336187471834 60565:60565 +0.00011266336187471834 56999:56999 +0.00011266336187471834 57233:57233 +0.00011266336187471834 33394:33394 +0.00011266336187471834 33073:33073 +0.00011266336187471834 57148:57148 +0.00011266336187471834 34848:34848 +0.00011266336187471834 56725:56725 +0.00011266336187471834 59673:59673 +0.00011266336187471834 55849:55849 +0.00011266336187471834 58975:58975 +0.00011266336187471834 34095:34095 +0.00011266336187471834 58594:58594 +0.00011266336187471834 56359:56359 +0.00011266336187471834 57762:57762 +0.00011266336187471834 58697:58697 +0.00011266336187471834 58560:58560 +0.00011266336187471834 35071:35071 +0.00011266336187471834 55676:55676 +0.00011266336187471834 58026:58026 +0.00011266336187471834 57497:57497 +0.00011266336187471834 33025:33025 +0.00011266336187471834 60828:60828 +0.00011266336187471834 57653:57653 +0.00011266336187471834 34127:34127 +0.00011266336187471834 60511:60511 +0.00011266336187471834 57960:57960 +0.00011266336187471834 58809:58809 +0.00011266336187471834 35505:35505 +0.00011266336187471834 33565:33565 +0.00011266336187471834 59419:59419 +0.00011266336187471834 59558:59558 +0.00011266336187471834 56537:56537 +0.00011266336187471834 58586:58586 +0.00011266336187471834 55726:55726 +0.00011266336187471834 58938:58938 +0.00011266336187471834 56201:56201 +0.00011266336187471834 55946:55946 +0.00011266336187471834 59482:59482 +0.00011266336187471834 34016:34016 +0.00011266336187471834 58080:58080 +0.00011266336187471834 33554:33554 +0.00011266336187471834 59840:59840 +0.00011266336187471834 58742:58742 +0.00011266336187471834 56899:56899 +0.00011266336187471834 56113:56113 +0.00011266336187471834 35058:35058 +0.00011266336187471834 35033:35033 +0.00011266336187471834 34014:34014 +0.00011266336187471834 33688:33688 +0.00011266336187471834 60090:60090 +0.00011266336187471834 59106:59106 +0.00011266336187471834 60052:60052 +0.00011266336187471834 34208:34208 +0.00011266336187471834 33322:33322 +0.00011266336187471834 32989:32989 +0.00011266336187471834 60877:60877 +0.00011266336187471834 60672:60672 +0.00011266336187471834 56797:56797 +0.00011266336187471834 56190:56190 +0.00011266336187471834 59782:59782 +0.00011266336187471834 33810:33810 +0.00011266336187471834 32877:32877 +0.00011266336187471834 59771:59771 +0.00011266336187471834 59500:59500 +0.00011266336187471834 55720:55720 +0.00011266336187471834 34729:34729 +0.00011266336187471834 58722:58722 +0.00011266336187471834 34877:34877 +0.00011266336187471834 57142:57142 +0.00011266336187471834 57236:57236 +0.00011266336187471834 57482:57482 +0.00011266336187471834 59742:59742 +0.00011266336187471834 59311:59311 +0.00011266336187471834 58142:58142 +0.00011266336187471834 55677:55677 +0.00011266336187471834 33013:33013 +0.00011266336187471834 59216:59216 +0.00011266336187471834 60412:60412 +0.00011266336187471834 60492:60492 +0.00011266336187471834 57167:57167 +0.00011266336187471834 33213:33213 +0.00011266336187471834 57744:57744 +0.00011266336187471834 34494:34494 +0.00011266336187471834 59729:59729 +0.00011266336187471834 33268:33268 +0.00011266336187471834 60315:60315 +0.00011266336187471834 60741:60741 +0.00011266336187471834 60270:60270 +0.00011266336187471834 58298:58298 +0.00011266336187471834 33844:33844 +0.00011266336187471834 60233:60233 +0.00011266336187471834 59019:59019 +0.00011266336187471834 33762:33762 +0.00011266336187471834 57658:57658 +0.00011266336187471834 58308:58308 +0.00011266336187471834 58127:58127 +0.00011266336187471834 56294:56294 +0.00011266336187471834 34558:34558 +0.00011266336187471834 57272:57272 +0.00011266336187471834 55644:55644 +0.00011266336187471834 34658:34658 +0.00011266336187471834 59538:59538 +0.00011266336187471834 59228:59228 +0.00011266336187471834 34485:34485 +0.00011266336187471834 55799:55799 +0.00011266336187471834 56584:56584 +0.00011266336187471834 55978:55978 +0.00011266336187471834 32861:32861 +0.00011266336187471834 35222:35222 +0.00011266336187471834 56013:56013 +0.00011266336187471834 55669:55669 +0.00011266336187471834 34685:34685 +0.00011266336187471834 34041:34041 +0.00011266336187471834 34389:34389 +0.00011266336187471834 58200:58200 +0.00011266336187471834 35538:35538 +0.00011266336187471834 56005:56005 +0.00011266336187471834 33921:33921 +0.00011266336187471834 58147:58147 +0.00011266336187471834 34846:34846 +0.00011266336187471834 60516:60516 +0.00011266336187471834 60224:60224 +0.00011266336187471834 58527:58527 +0.00011266336187471834 35208:35208 +0.00011266336187471834 33981:33981 +0.00011266336187471834 59350:59350 +0.00011266336187471834 56132:56132 +0.00011266336187471834 33536:33536 +0.00011266336187471834 34733:34733 +0.00011266336187471834 60127:60127 +0.00011266336187471834 33508:33508 +0.00011266336187471834 57258:57258 +0.00011266336187471834 34344:34344 +0.00011266336187471834 57323:57323 +0.00011266336187471834 34850:34850 +0.00011266336187471834 59777:59777 +0.00011266336187471834 59750:59750 +0.00011266336187471834 32802:32802 +0.00011266336187471834 57212:57212 +0.00011266336187471834 56288:56288 +0.00011266336187471834 57016:57016 +0.00011266336187471834 35123:35123 +0.00011266336187471834 33467:33467 +0.00011266336187471834 35152:35152 +0.00011266336187471834 34272:34272 +0.00011266336187471834 33102:33102 +0.00011266336187471834 60550:60550 +0.00011266336187471834 57462:57462 +0.00011266336187471834 58646:58646 +0.00011266336187471834 35195:35195 +0.00011266336187471834 57725:57725 +0.00011266336187471834 35048:35048 +0.00011266336187471834 56889:56889 +0.00011266336187471834 33675:33675 +0.00011266336187471834 57567:57567 +0.00011266336187471834 35163:35163 +0.00011266336187471834 34297:34297 +0.00011266336187471834 34822:34822 +0.00011266336187471834 56726:56726 +0.00011266336187471834 57191:57191 +0.00011266336187471834 34058:34058 +0.00011266336187471834 57059:57059 +0.00011266336187471834 34566:34566 +0.00011266336187471834 55896:55896 +0.00011266336187471834 57189:57189 +0.00011266336187471834 34765:34765 +0.00011266336187471834 34612:34612 +0.00011266336187471834 56629:56629 +0.00011266336187471834 34843:34843 +0.00011266336187471834 58348:58348 +0.00011266336187471834 58777:58777 +0.00011266336187471834 33780:33780 +0.00011266336187471834 59098:59098 +0.00011266336187471834 55612:55612 +0.00011266336187471834 58562:58562 +0.00011266336187471834 35363:35363 +0.00011266336187471834 56568:56568 +0.00011266336187471834 33396:33396 +0.00011266336187471834 33363:33363 +0.00011266336187471834 55918:55918 +0.00011266336187471834 57320:57320 +0.00011266336187471834 35440:35440 +0.00011266336187471834 59481:59481 +0.00011266336187471834 59326:59326 +0.00011266336187471834 35030:35030 +0.00011266336187471834 60296:60296 +0.00011266336187471834 59116:59116 +0.00011266336187471834 59277:59277 +0.00011266336187471834 56939:56939 +0.00011266336187471834 33260:33260 +0.00011266336187471834 59932:59932 +0.00011266336187471834 59593:59593 +0.00011266336187471834 57755:57755 +0.00011266336187471834 60400:60400 +0.00011266336187471834 32978:32978 +0.00011266336187471834 34791:34791 +0.00011266336187471834 56091:56091 +0.00011266336187471834 59497:59497 +0.00011266336187471834 35240:35240 +0.00011266336187471834 34487:34487 +0.00011266336187471834 34415:34415 +0.00011266336187471834 60402:60402 +0.00011266336187471834 56301:56301 +0.00011266336187471834 58489:58489 +0.00011266336187471834 59900:59900 +0.00011266336187471834 56644:56644 +0.00011266336187471834 58696:58696 +0.00011266336187471834 34777:34777 +0.00011266336187471834 56074:56074 +0.00011266336187471834 33259:33259 +0.00011266336187471834 33877:33877 +0.00011266336187471834 58921:58921 +0.00011266336187471834 56956:56956 +0.00011266336187471834 56256:56256 +0.00011266336187471834 55908:55908 +0.00011266336187471834 34374:34374 +0.00011266336187471834 58829:58829 +0.00011266336187471834 58754:58754 +0.00011266336187471834 35394:35394 +0.00011266336187471834 34956:34956 +0.00011266336187471834 33961:33961 +0.00011266336187471834 55790:55790 +0.00011266336187471834 58163:58163 +0.00011266336187471834 35088:35088 +0.00011266336187471834 58675:58675 +0.00011266336187471834 60822:60822 +0.00011266336187471834 57231:57231 +0.00011266336187471834 55608:55608 +0.00011266336187471834 59205:59205 +0.00011266336187471834 59489:59489 +0.00011266336187471834 57215:57215 +0.00011266336187471834 59626:59626 +0.00011266336187471834 35543:35543 +0.00011266336187471834 59247:59247 +0.00011266336187471834 33740:33740 +0.00011266336187471834 60512:60512 +0.00011266336187471834 60275:60275 +0.00011266336187471834 56977:56977 +0.00011266336187471834 56556:56556 +0.00011266336187471834 34247:34247 +0.00011266336187471834 60791:60791 +0.00011266336187471834 33735:33735 +0.00011266336187471834 60304:60304 +0.00011266336187471834 56411:56411 +0.00011266336187471834 33743:33743 +0.00011266336187471834 33249:33249 +0.00011266336187471834 59641:59641 +0.00011266336187471834 60444:60444 +0.00011266336187471834 34786:34786 +0.00011266336187471834 60463:60463 +0.00011266336187471834 56041:56041 +0.00011266336187471834 57610:57610 +0.00011266336187471834 56059:56059 +0.00011266336187471834 59870:59870 +0.00011266336187471834 34867:34867 +0.00011266336187471834 58724:58724 +0.00011266336187471834 58056:58056 +0.00011266336187471834 55916:55916 +0.00011266336187471834 58603:58603 +0.00011266336187471834 56863:56863 +0.00011266336187471834 33233:33233 +0.00011266336187471834 56525:56525 +0.00011266336187471834 60858:60858 +0.00011266336187471834 58880:58880 +0.00011266336187471834 57356:57356 +0.00011266336187471834 33059:33059 +0.00011266336187471834 60980:60980 +0.00011266336187471834 57262:57262 +0.00011266336187471834 34642:34642 +0.00011266336187471834 33098:33098 +0.00011266336187471834 59753:59753 +0.00011266336187471834 35442:35442 +0.00011266336187471834 55801:55801 +0.00011266336187471834 59547:59547 +0.00011266336187471834 35391:35391 +0.00011266336187471834 34898:34898 +0.00011266336187471834 57509:57509 +0.00011266336187471834 35254:35254 +0.00011266336187471834 34240:34240 +0.00011266336187471834 55917:55917 +0.00011266336187471834 58296:58296 +0.00011266336187471834 57765:57765 +0.00011266336187471834 59061:59061 +0.00011266336187471834 57378:57378 +0.00011266336187471834 32993:32993 +0.00011266336187471834 33005:33005 +0.00011266336187471834 33569:33569 +0.00011266336187471834 34067:34067 +0.00011266336187471834 58725:58725 +0.00011266336187471834 60254:60254 +0.00011266336187471834 56202:56202 +0.00011266336187471834 33907:33907 +0.00011266336187471834 34904:34904 +0.00011266336187471834 33434:33434 +0.00011266336187471834 58530:58530 +0.00011266336187471834 34866:34866 +0.00011266336187471834 34223:34223 +0.00011266336187471834 58573:58573 +0.00011266336187471834 59974:59974 +0.00011266336187471834 58262:58262 +0.00011266336187471834 57652:57652 +0.00011266336187471834 59015:59015 +0.00011266336187471834 55891:55891 +0.00011266336187471834 55786:55786 +0.00011266336187471834 34341:34341 +0.00011266336187471834 58989:58989 +0.00011266336187471834 57663:57663 +0.00011266336187471834 56400:56400 +0.00011266336187471834 32815:32815 +0.00011266336187471834 35110:35110 +0.00011266336187471834 56137:56137 +0.00011266336187471834 33560:33560 +0.00011266336187471834 58432:58432 +0.00011266336187471834 34394:34394 +0.00011266336187471834 33976:33976 +0.00011266336187471834 56183:56183 +0.00011266336187471834 56032:56032 +0.00011266336187471834 57273:57273 +0.00011266336187471834 34781:34781 +0.00011266336187471834 60567:60567 +0.00011266336187471834 57621:57621 +0.00011266336187471834 55770:55770 +0.00011266336187471834 33278:33278 +0.00011266336187471834 60973:60973 +0.00011266336187471834 60993:60993 +0.00011266336187471834 33026:33026 +0.00011266336187471834 58949:58949 +0.00011266336187471834 33177:33177 +0.00011266336187471834 57968:57968 +0.00011266336187471834 57252:57252 +0.00011266336187471834 35405:35405 +0.00011266336187471834 33884:33884 +0.00011266336187471834 59384:59384 +0.00011266336187471834 34256:34256 +0.00011266336187471834 59586:59586 +0.00011266336187471834 59966:59966 +0.00011266336187471834 33519:33519 +0.00011266336187471834 57288:57288 +0.00011266336187471834 34687:34687 +0.00011266336187471834 57136:57136 +0.00011266336187471834 57064:57064 +0.00011266336187471834 33443:33443 +0.00011266336187471834 56892:56892 +0.00011266336187471834 56331:56331 +0.00011266336187471834 57073:57073 +0.00011266336187471834 60498:60498 +0.00011266336187471834 33551:33551 +0.00011266336187471834 60117:60117 +0.00011266336187471834 35032:35032 +0.00011266336187471834 57817:57817 +0.00011266336187471834 55732:55732 +0.00011266336187471834 33733:33733 +0.00011266336187471834 57754:57754 +0.00011266336187471834 56524:56524 +0.00011266336187471834 57214:57214 +0.00011266336187471834 59080:59080 +0.00011266336187471834 56454:56454 +0.00011266336187471834 59579:59579 +0.00011266336187471834 59935:59935 +0.00011266336187471834 34142:34142 +0.00011266336187471834 59862:59862 +0.00011266336187471834 56226:56226 +0.00011266336187471834 35146:35146 +0.00011266336187471834 33424:33424 +0.00011266336187471834 59488:59488 +0.00011266336187471834 58794:58794 +0.00011266336187471834 60034:60034 +0.00011266336187471834 33512:33512 +0.00011266336187471834 35236:35236 +0.00011266336187471834 33300:33300 +0.00011266336187471834 55934:55934 +0.00011266336187471834 34830:34830 +0.00011266336187471834 59965:59965 +0.00011266336187471834 57366:57366 +0.00011266336187471834 56849:56849 +0.00011266336187471834 33761:33761 +0.00011266336187471834 32786:32786 +0.00011266336187471834 60762:60762 +0.00011266336187471834 56386:56386 +0.00011266336187471834 35437:35437 +0.00011266336187471834 34100:34100 +0.00011266336187471834 32866:32866 +0.00011266336187471834 59126:59126 +0.00011266336187471834 56509:56509 +0.00011266336187471834 32806:32806 +0.00011266336187471834 56829:56829 +0.00011266336187471834 60345:60345 +0.00011266336187471834 59303:59303 +0.00011266336187471834 60733:60733 +0.00011266336187471834 59038:59038 +0.00011266336187471834 59860:59860 +0.00011266336187471834 60784:60784 +0.00011266336187471834 58616:58616 +0.00011266336187471834 55782:55782 +0.00011266336187471834 60094:60094 +0.00011266336187471834 58906:58906 +0.00011266336187471834 60880:60880 +0.00011266336187471834 56965:56965 +0.00011266336187471834 60663:60663 +0.00011266336187471834 58438:58438 +0.00011266336187471834 56465:56465 +0.00011266336187471834 34672:34672 +0.00011266336187471834 60981:60981 +0.00011266336187471834 57954:57954 +0.00011266336187471834 60347:60347 +0.00011266336187471834 35113:35113 +0.00011266336187471834 55773:55773 +0.00011266336187471834 35414:35414 +0.00011266336187471834 33940:33940 +0.00011266336187471834 59208:59208 +0.00011266336187471834 56125:56125 +0.00011266336187471834 32788:32788 +0.00011266336187471834 55827:55827 +0.00011266336187471834 34679:34679 +0.00011266336187471834 58099:58099 +0.00011266336187471834 32777:32777 +0.00011266336187471834 32995:32995 +0.00011266336187471834 35012:35012 +0.00011266336187471834 57618:57618 +0.00011266336187471834 35089:35089 +0.00011266336187471834 59917:59917 +0.00011266336187471834 56051:56051 +0.00011266336187471834 60392:60392 +0.00011266336187471834 58626:58626 +0.00011266336187471834 58259:58259 +0.00011266336187471834 56065:56065 +0.00011266336187471834 58736:58736 +0.00011266336187471834 56516:56516 +0.00011266336187471834 56253:56253 +0.00011266336187471834 34797:34797 +0.00011266336187471834 34061:34061 +0.00011266336187471834 58084:58084 +0.00011266336187471834 34439:34439 +0.00011266336187471834 34335:34335 +0.00011266336187471834 33652:33652 +0.00011266336187471834 34107:34107 +0.00011266336187471834 60327:60327 +0.00011266336187471834 60863:60863 +0.00011266336187471834 56798:56798 +0.00011266336187471834 33734:33734 +0.00011266336187471834 58667:58667 +0.00011266336187471834 60523:60523 +0.00011266336187471834 58635:58635 +0.00011266336187471834 56757:56757 +0.00011266336187471834 59756:59756 +0.00011266336187471834 35065:35065 +0.00011266336187471834 58409:58409 +0.00011266336187471834 55787:55787 +0.00011266336187471834 60943:60943 +0.00011266336187471834 60660:60660 +0.00011266336187471834 57911:57911 +0.00011266336187471834 57246:57246 +0.00011266336187471834 34186:34186 +0.00011266336187471834 59849:59849 +0.00011266336187471834 34117:34117 +0.00011266336187471834 57118:57118 +0.00011266336187471834 33085:33085 +0.00011266336187471834 60419:60419 +0.00011266336187471834 58813:58813 +0.00011266336187471834 58797:58797 +0.00011266336187471834 32979:32979 +0.00011266336187471834 56713:56713 +0.00011266336187471834 57499:57499 +0.00011266336187471834 57561:57561 +0.00011266336187471834 56551:56551 +0.00011266336187471834 56176:56176 +0.00011266336187471834 33725:33725 +0.00011266336187471834 33234:33234 +0.00011266336187471834 34268:34268 +0.00011266336187471834 56251:56251 +0.00011266336187471834 60156:60156 +0.00011266336187471834 33425:33425 +0.00011266336187471834 34862:34862 +0.00011266336187471834 34622:34622 +0.00011266336187471834 34021:34021 +0.00011266336187471834 33081:33081 +0.00011266336187471834 58243:58243 +0.00011266336187471834 32969:32969 +0.00011266336187471834 57326:57326 +0.00011266336187471834 57565:57565 +0.00011266336187471834 55945:55945 +0.00011266336187471834 56402:56402 +0.00011266336187471834 59044:59044 +0.00011266336187471834 56116:56116 +0.00011266336187471834 58980:58980 +0.00011266336187471834 57213:57213 +0.00011266336187471834 59994:59994 +0.00011266336187471834 34491:34491 +0.00011266336187471834 57121:57121 +0.00011266336187471834 57689:57689 +0.00011266336187471834 35038:35038 +0.00011266336187471834 58605:58605 +0.00011266336187471834 56613:56613 +0.00011266336187471834 34379:34379 +0.00011266336187471834 33196:33196 +0.00011266336187471834 59552:59552 +0.00011266336187471834 58350:58350 +0.00011266336187471834 34212:34212 +0.00011266336187471834 33486:33486 +0.00011266336187471834 57519:57519 +0.00011266336187471834 57364:57364 +0.00011266336187471834 56355:56355 +0.00011266336187471834 34713:34713 +0.00011266336187471834 60875:60875 +0.00011266336187471834 34818:34818 +0.00011266336187471834 59977:59977 +0.00011266336187471834 59100:59100 +0.00011266336187471834 60915:60915 +0.00011266336187471834 35350:35350 +0.00011266336187471834 57158:57158 +0.00011266336187471834 59653:59653 +0.00011266336187471834 57125:57125 +0.00011266336187471834 56087:56087 +0.00011266336187471834 33905:33905 +0.00011266336187471834 32928:32928 +0.00011266336187471834 59090:59090 +0.00011266336187471834 60237:60237 +0.00011266336187471834 58402:58402 +0.00011266336187471834 34121:34121 +0.00011266336187471834 34175:34175 +0.00011266336187471834 56628:56628 +0.00011266336187471834 55742:55742 +0.00011266336187471834 60614:60614 +0.00011266336187471834 57457:57457 +0.00011266336187471834 60284:60284 +0.00011266336187471834 59745:59745 +0.00011266336187471834 56374:56374 +0.00011266336187471834 34138:34138 +0.00011266336187471834 60904:60904 +0.00011266336187471834 58359:58359 +0.00011266336187471834 59266:59266 +0.00011266336187471834 56532:56532 +0.00011266336187471834 58913:58913 +0.00011266336187471834 34984:34984 +0.00011266336187471834 59972:59972 +0.00011266336187471834 59179:59179 +0.00011266336187471834 33309:33309 +0.00011266336187471834 57083:57083 +0.00011266336187471834 55607:55607 +0.00011266336187471834 34589:34589 +0.00011266336187471834 60738:60738 +0.00011266336187471834 57583:57583 +0.00011266336187471834 56232:56232 +0.00011266336187471834 33469:33469 +0.00011266336187471834 59351:59351 +0.00011266336187471834 57433:57433 +0.00011266336187471834 60955:60955 +0.00011266336187471834 56612:56612 +0.00011266336187471834 60352:60352 +0.00011266336187471834 56070:56070 +0.00011266336187471834 33029:33029 +0.00011266336187471834 32871:32871 +0.00011266336187471834 34661:34661 +0.00011266336187471834 59310:59310 +0.00011266336187471834 60129:60129 +0.00011266336187471834 35156:35156 +0.00011266336187471834 33728:33728 +0.00011266336187471834 34790:34790 +0.00011266336187471834 33422:33422 +0.00011266336187471834 34204:34204 +0.00011266336187471834 58738:58738 +0.00011266336187471834 57805:57805 +0.00011266336187471834 59058:59058 +0.00011266336187471834 35395:35395 +0.00011266336187471834 33926:33926 +0.00011266336187471834 33801:33801 +0.00011266336187471834 59282:59282 +0.00011266336187471834 57047:57047 +0.00011266336187471834 33993:33993 +0.00011266336187471834 57853:57853 +0.00011266336187471834 33767:33767 +0.00011266336187471834 60667:60667 +0.00011266336187471834 60435:60435 +0.00011266336187471834 59102:59102 +0.00011266336187471834 59174:59174 +0.00011266336187471834 57683:57683 +0.00011266336187471834 60289:60289 +0.00011266336187471834 34362:34362 +0.00011266336187471834 56089:56089 +0.00011266336187471834 60851:60851 +0.00011266336187471834 33805:33805 +0.00011266336187471834 34874:34874 +0.00011266336187471834 60855:60855 +0.00011266336187471834 59698:59698 +0.00011266336187471834 34185:34185 +0.00011266336187471834 33055:33055 +0.00011266336187471834 33313:33313 +0.00011266336187471834 33662:33662 +0.00011266336187471834 60299:60299 +0.00011266336187471834 34210:34210 +0.00011266336187471834 35299:35299 +0.00011266336187471834 59373:59373 +0.00011266336187471834 35214:35214 +0.00011266336187471834 33145:33145 +0.00011266336187471834 58415:58415 +0.00011266336187471834 57793:57793 +0.00011266336187471834 34888:34888 +0.00011266336187471834 33022:33022 +0.00011266336187471834 56539:56539 +0.00011266336187471834 59607:59607 +0.00011266336187471834 34327:34327 +0.00011266336187471834 60467:60467 +0.00011266336187471834 58309:58309 +0.00011266336187471834 56563:56563 +0.00011266336187471834 57547:57547 +0.00011266336187471834 34949:34949 +0.00011266336187471834 34738:34738 +0.00011266336187471834 58463:58463 +0.00011266336187471834 56000:56000 +0.00011266336187471834 60771:60771 +0.00011266336187471834 58745:58745 +0.00011266336187471834 34382:34382 +0.00011266336187471834 60389:60389 +0.00011266336187471834 56641:56641 +0.00011266336187471834 33480:33480 +0.00011266336187471834 33461:33461 +0.00011266336187471834 60333:60333 +0.00011266336187471834 60048:60048 +0.00011266336187471834 56566:56566 +0.00011266336187471834 59178:59178 +0.00011266336187471834 58867:58867 +0.00011266336187471834 60812:60812 +0.00011266336187471834 59411:59411 +0.00011266336187471834 57859:57859 +0.00011266336187471834 59249:59249 +0.00011266336187471834 57570:57570 +0.00011266336187471834 33567:33567 +0.00011266336187471834 32921:32921 +0.00011266336187471834 34510:34510 +0.00011266336187471834 57617:57617 +0.00011266336187471834 59082:59082 +0.00011266336187471834 57801:57801 +0.00011266336187471834 34917:34917 +0.00011266336187471834 34798:34798 +0.00011266336187471834 34162:34162 +0.00011266336187471834 60997:60997 +0.00011266336187471834 56467:56467 +0.00011266336187471834 57936:57936 +0.00011266336187471834 56384:56384 +0.00011266336187471834 34576:34576 +0.00011266336187471834 33524:33524 +0.00011266336187471834 59022:59022 +0.00011266336187471834 58752:58752 +0.00011266336187471834 59370:59370 +0.00011266336187471834 57340:57340 +0.00011266336187471834 59585:59585 +0.00011266336187471834 59834:59834 +0.00011266336187471834 34152:34152 +0.00011266336187471834 34950:34950 +0.00011266336187471834 55662:55662 +0.00011266336187471834 33238:33238 +0.00011266336187471834 59734:59734 +0.00011266336187471834 57896:57896 +0.00011266336187471834 57955:57955 +0.00011266336187471834 34792:34792 +0.00011266336187471834 57771:57771 +0.00011266336187471834 56815:56815 +0.00011266336187471834 33865:33865 +0.00011266336187471834 33621:33621 +0.00011266336187471834 57044:57044 +0.00011266336187471834 35429:35429 +0.00011266336187471834 57129:57129 +0.00011266336187471834 33129:33129 +0.00011266336187471834 60549:60549 +0.00011266336187471834 57875:57875 +0.00011266336187471834 57872:57872 +0.00011266336187471834 59991:59991 +0.00011266336187471834 33117:33117 +0.00011266336187471834 59165:59165 +0.00011266336187471834 56891:56891 +0.00011266336187471834 58249:58249 +0.00011266336187471834 57228:57228 +0.00011266336187471834 56136:56136 +0.00011266336187471834 60786:60786 +0.00011266336187471834 35232:35232 +0.00011266336187471834 33484:33484 +0.00011266336187471834 60277:60277 +0.00011266336187471834 35083:35083 +0.00011266336187471834 34517:34517 +0.00011266336187471834 60604:60604 +0.00011266336187471834 59931:59931 +0.00011266336187471834 35062:35062 +0.00011266336187471834 60602:60602 +0.00011266336187471834 35041:35041 +0.00011266336187471834 33126:33126 +0.00011266336187471834 33187:33187 +0.00011266336187471834 59281:59281 +0.00011266336187471834 33764:33764 +0.00011266336187471834 59666:59666 +0.00011266336187471834 59152:59152 +0.00011266336187471834 57299:57299 +0.00011266336187471834 35184:35184 +0.00011266336187471834 57630:57630 +0.00011266336187471834 57290:57290 +0.00011266336187471834 57647:57647 +0.00011266336187471834 59694:59694 +0.00011266336187471834 35170:35170 +0.00011266336187471834 34467:34467 +0.00011266336187471834 33954:33954 +0.00011266336187471834 33186:33186 +0.00011266336187471834 60746:60746 +0.00011266336187471834 58009:58009 +0.00011266336187471834 60316:60316 +0.00011266336187471834 57067:57067 +0.00011266336187471834 56486:56486 +0.00011266336187471834 34296:34296 +0.00011266336187471834 33771:33771 +0.00011266336187471834 34638:34638 +0.00011266336187471834 56414:56414 +0.00011266336187471834 59548:59548 +0.00011266336187471834 33947:33947 +0.00011266336187471834 34171:34171 +0.00011266336187471834 56796:56796 +0.00011266336187471834 33564:33564 +0.00011266336187471834 59359:59359 +0.00011266336187471834 56245:56245 +0.00011266336187471834 59843:59843 +0.00011266336187471834 33846:33846 +0.00011266336187471834 55883:55883 +0.00011266336187471834 57992:57992 +0.00011266336187471834 57551:57551 +0.00011266336187471834 56042:56042 +0.00011266336187471834 33079:33079 +0.00011266336187471834 60927:60927 +0.00011266336187471834 56938:56938 +0.00011266336187471834 59188:59188 +0.00011266336187471834 56014:56014 +0.00011266336187471834 34484:34484 +0.00011266336187471834 59029:59029 +0.00011266336187471834 56690:56690 +0.00011266336187471834 58429:58429 +0.00011266336187471834 59430:59430 +0.00011266336187471834 56242:56242 +0.00011266336187471834 33083:33083 +0.00011266336187471834 59768:59768 +0.00011266336187471834 57672:57672 +0.00011266336187471834 34782:34782 +0.00011266336187471834 58204:58204 +0.00011266336187471834 34276:34276 +0.00011266336187471834 35094:35094 +0.00011266336187471834 34363:34363 +0.00011266336187471834 58121:58121 +0.00011266336187471834 35180:35180 +0.00011266336187471834 35131:35131 +0.00011266336187471834 57056:57056 +0.00011266336187471834 56381:56381 +0.00011266336187471834 60777:60777 +0.00011266336187471834 33027:33027 +0.00011266336187471834 33194:33194 +0.00011266336187471834 60374:60374 +0.00011266336187471834 34195:34195 +0.00011266336187471834 58546:58546 +0.00011266336187471834 56632:56632 +0.00011266336187471834 34979:34979 +0.00011266336187471834 57387:57387 +0.00011266336187471834 56241:56241 +0.00011266336187471834 57665:57665 +0.00011266336187471834 33299:33299 +0.00011266336187471834 35445:35445 +0.00011266336187471834 34206:34206 +0.00011266336187471834 59948:59948 +0.00011266336187471834 59103:59103 +0.00011266336187471834 58967:58967 +0.00011266336187471834 34561:34561 +0.00011266336187471834 58729:58729 +0.00011266336187471834 56028:56028 +0.00011266336187471834 58762:58762 +0.00011266336187471834 35501:35501 +0.00011266336187471834 58191:58191 +0.00011266336187471834 55721:55721 +0.00011266336187471834 59305:59305 +0.00011266336187471834 34170:34170 +0.00011266336187471834 55625:55625 +0.00011266336187471834 60464:60464 +0.00011266336187471834 58304:58304 +0.00011266336187471834 55954:55954 +0.00011266336187471834 59352:59352 +0.00011266336187471834 56329:56329 +0.00011266336187471834 60455:60455 +0.00011266336187471834 58570:58570 +0.00011266336187471834 35553:35553 +0.00011266336187471834 35408:35408 +0.00011266336187471834 59762:59762 +0.00011266336187471834 33672:33672 +0.00011266336187471834 58008:58008 +0.00011266336187471834 59876:59876 +0.00011266336187471834 59661:59661 +0.00011266336187471834 59046:59046 +0.00011266336187471834 57464:57464 +0.00011266336187471834 59597:59597 +0.00011266336187471834 55957:55957 +0.00011266336187471834 60330:60330 +0.00011266336187471834 58326:58326 +0.00011266336187471834 56998:56998 +0.00011266336187471834 35145:35145 +0.00011266336187471834 60832:60832 +0.00011266336187471834 58974:58974 +0.00011266336187471834 35398:35398 +0.00011266336187471834 35008:35008 +0.00011266336187471834 58700:58700 +0.00011266336187471834 33899:33899 +0.00011266336187471834 34554:34554 +0.00011266336187471834 60099:60099 +0.00011266336187471834 58112:58112 +0.00011266336187471834 34292:34292 +0.00011266336187471834 57039:57039 +0.00011266336187471834 55847:55847 +0.00011266336187471834 33655:33655 +0.00011266336187471834 58284:58284 +0.00011266336187471834 57697:57697 +0.00011266336187471834 59831:59831 +0.00011266336187471834 59744:59744 +0.00011266336187471834 33511:33511 +0.00011266336187471834 55836:55836 +0.00011266336187471834 60799:60799 +0.00011266336187471834 59758:59758 +0.00011266336187471834 58302:58302 +0.00011266336187471834 34805:34805 +0.00011266336187471834 55788:55788 +0.00011266336187471834 60671:60671 +0.00011266336187471834 59531:59531 +0.00011266336187471834 58501:58501 +0.00011266336187471834 55997:55997 +0.00011266336187471834 60206:60206 +0.00011266336187471834 59182:59182 +0.00011266336187471834 58437:58437 +0.00011266336187471834 57575:57575 +0.00011266336187471834 60414:60414 +0.00011266336187471834 32869:32869 +0.00011266336187471834 35122:35122 +0.00011266336187471834 34596:34596 +0.00011266336187471834 57450:57450 +0.00011266336187471834 33958:33958 +0.00011266336187471834 34069:34069 +0.00011266336187471834 56010:56010 +0.00011266336187471834 56935:56935 +0.00011266336187471834 60802:60802 +0.00011266336187471834 59272:59272 +0.00011266336187471834 56062:56062 +0.00011266336187471834 56020:56020 +0.00011266336187471834 57556:57556 +0.00011266336187471834 59071:59071 +0.00011266336187471834 59246:59246 +0.00011266336187471834 34803:34803 +0.00011266336187471834 58500:58500 +0.00011266336187471834 56341:56341 +0.00011266336187471834 34594:34594 +0.00011266336187471834 60100:60100 +0.00011266336187471834 34708:34708 +0.00011266336187471834 59942:59942 +0.00011266336187471834 57977:57977 +0.00011266336187471834 55671:55671 +0.00011266336187471834 59769:59769 +0.00011266336187471834 58242:58242 +0.00011266336187471834 60015:60015 +0.00011266336187471834 56305:56305 +0.00011266336187471834 60232:60232 +0.00011266336187471834 33984:33984 +0.00011266336187471834 35453:35453 +0.00011266336187471834 59871:59871 +0.00011266336187471834 57737:57737 +0.00011266336187471834 57444:57444 +0.00011266336187471834 56352:56352 +0.00011266336187471834 60885:60885 +0.00011266336187471834 57031:57031 +0.00011266336187471834 58924:58924 +0.00011266336187471834 56626:56626 +0.00011266336187471834 55989:55989 +0.00011266336187471834 56458:56458 +0.00011266336187471834 58245:58245 +0.00011266336187471834 32970:32970 +0.00011266336187471834 58761:58761 +0.00011266336187471834 57277:57277 +0.00011266336187471834 56729:56729 +0.00011266336187471834 59541:59541 +0.00011266336187471834 57484:57484 +0.00011266336187471834 34976:34976 +0.00011266336187471834 34967:34967 +0.00011266336187471834 34492:34492 +0.00011266336187471834 35381:35381 +0.00011266336187471834 34538:34538 +0.00011266336187471834 59276:59276 +0.00011266336187471834 32997:32997 +0.00011266336187471834 55982:55982 +0.00011266336187471834 34224:34224 +0.00011266336187471834 57028:57028 +0.00011266336187471834 55905:55905 +0.00011266336187471834 59372:59372 +0.00011266336187471834 35397:35397 +0.00011266336187471834 34316:34316 +0.00011266336187471834 60773:60773 +0.00011266336187471834 33840:33840 +0.00011266336187471834 58854:58854 +0.00011266336187471834 57261:57261 +0.00011266336187471834 33781:33781 +0.00011266336187471834 59722:59722 +0.00011266336187471834 33969:33969 +0.00011266336187471834 35061:35061 +0.00011266336187471834 34591:34591 +0.00011266336187471834 56886:56886 +0.00011266336187471834 32784:32784 +0.00011266336187471834 56840:56840 +0.00011266336187471834 34968:34968 +0.00011266336187471834 56421:56421 +0.00011266336187471834 56079:56079 +0.00011266336187471834 56722:56722 +0.00011266336187471834 56149:56149 +0.00011266336187471834 57657:57657 +0.00011266336187471834 35168:35168 +0.00011266336187471834 33700:33700 +0.00011266336187471834 58712:58712 +0.00011266336187471834 56037:56037 +0.00011266336187471834 34495:34495 +0.00011266336187471834 55857:55857 +0.00011266336187471834 57087:57087 +0.00011266336187471834 57868:57868 +0.00011266336187471834 33864:33864 +0.00011266336187471834 32876:32876 +0.00011266336187471834 34982:34982 +0.00011266336187471834 32875:32875 +0.00011266336187471834 59283:59283 +0.00011266336187471834 56398:56398 +0.00011266336187471834 34851:34851 +0.00011266336187471834 33858:33858 +0.00011266336187471834 60845:60845 +0.00011266336187471834 56133:56133 +0.00011266336187471834 33724:33724 +0.00011266336187471834 57939:57939 +0.00011266336187471834 56983:56983 +0.00011266336187471834 34433:34433 +0.00011266336187471834 33634:33634 +0.00011266336187471834 60286:60286 +0.00011266336187471834 35525:35525 +0.00011266336187471834 34945:34945 +0.00011266336187471834 56285:56285 +0.00011266336187471834 56806:56806 +0.00011266336187471834 56764:56764 +0.00011266336187471834 60719:60719 +0.00011266336187471834 35351:35351 +0.00011266336187471834 35183:35183 +0.00011266336187471834 55906:55906 +0.00011266336187471834 59560:59560 +0.00011266336187471834 32951:32951 +0.00011266336187471834 57043:57043 +0.00011266336187471834 60362:60362 +0.00011266336187471834 34151:34151 +0.00011266336187471834 33827:33827 +0.00011266336187471834 35490:35490 +0.00011266336187471834 34731:34731 +0.00011266336187471834 33797:33797 +0.00011266336187471834 59008:59008 +0.00011266336187471834 33052:33052 +0.00011266336187471834 57313:57313 +0.00011266336187471834 56986:56986 +0.00011266336187471834 33092:33092 +0.00011266336187471834 34704:34704 +0.00011266336187471834 60959:60959 +0.00011266336187471834 59431:59431 +0.00011266336187471834 56719:56719 +0.00011266336187471834 59601:59601 +0.00011266336187471834 35364:35364 +0.00011266336187471834 59785:59785 +0.00011266336187471834 58887:58887 +0.00011266336187471834 33654:33654 +0.00011266336187471834 60642:60642 +0.00011266336187471834 59403:59403 +0.00011266336187471834 58542:58542 +0.00011266336187471834 56196:56196 +0.00011266336187471834 57165:57165 +0.00011266336187471834 56480:56480 +0.00011266336187471834 33217:33217 +0.00011266336187471834 57825:57825 +0.00011266336187471834 57270:57270 +0.00011266336187471834 59470:59470 +0.00011266336187471834 33207:33207 +0.00011266336187471834 34552:34552 +0.00011266336187471834 35310:35310 +0.00011266336187471834 56291:56291 +0.00011266336187471834 56701:56701 +0.00011266336187471834 55831:55831 +0.00011266336187471834 33649:33649 +0.00011266336187471834 57523:57523 +0.00011266336187471834 56024:56024 +0.00011266336187471834 33067:33067 +0.00011266336187471834 55689:55689 +0.00011266336187471834 33209:33209 +0.00011266336187471834 60217:60217 +0.00011266336187471834 57930:57930 +0.00011266336187471834 33019:33019 +0.00011266336187471834 33008:33008 +0.00011266336187471834 34313:34313 +0.00011266336187471834 56343:56343 +0.00011266336187471834 32860:32860 +0.00011266336187471834 33550:33550 +0.00011266336187471834 58095:58095 +0.00011266336187471834 57924:57924 +0.00011266336187471834 56172:56172 +0.00011266336187471834 55952:55952 +0.00011266336187471834 34393:34393 +0.00011266336187471834 57361:57361 +0.00011266336187471834 57731:57731 +0.00011266336187471834 57958:57958 +0.00011266336187471834 60789:60789 +0.00011266336187471834 59811:59811 +0.00011266336187471834 35412:35412 +0.00011266336187471834 58234:58234 +0.00011266336187471834 32797:32797 +0.00011266336187471834 59644:59644 +0.00011266336187471834 57787:57787 +0.00011266336187471834 55696:55696 +0.00011266336187471834 57026:57026 +0.00011266336187471834 57952:57952 +0.00011266336187471834 32913:32913 +0.00011266336187471834 56567:56567 +0.00011266336187471834 34928:34928 +0.00011266336187471834 59998:59998 +0.00011266336187471834 57785:57785 +0.00011266336187471834 34690:34690 +0.00011266336187471834 34535:34535 +0.00011266336187471834 33190:33190 +0.00011266336187471834 34148:34148 +0.00011266336187471834 34006:34006 +0.00011266336187471834 58225:58225 +0.00011266336187471834 57650:57650 +0.00011266336187471834 56686:56686 +0.00011266336187471834 33312:33312 +0.00011266336187471834 60079:60079 +0.00011266336187471834 33274:33274 +0.00011266336187471834 60380:60380 +0.00011266336187471834 60292:60292 +0.00011266336187471834 60355:60355 +0.00011266336187471834 56974:56974 +0.00011266336187471834 60859:60859 +0.00011266336187471834 59845:59845 +0.00011266336187471834 58624:58624 +0.00011266336187471834 58073:58073 +0.00011266336187471834 57400:57400 +0.00011266336187471834 34780:34780 +0.00011266336187471834 58286:58286 +0.00011266336187471834 34919:34919 +0.00011266336187471834 58495:58495 +0.00011266336187471834 59983:59983 +0.00011266336187471834 57761:57761 +0.00011266336187471834 57916:57916 +0.00011266336187471834 56417:56417 +0.00011266336187471834 34590:34590 +0.00011266336187471834 35324:35324 +0.00011266336187471834 33453:33453 +0.00011266336187471834 57018:57018 +0.00011266336187471834 35409:35409 +0.00011266336187471834 56281:56281 +0.00011266336187471834 57100:57100 +0.00011266336187471834 56412:56412 +0.00011266336187471834 34568:34568 +0.00011266336187471834 33694:33694 +0.00011266336187471834 59523:59523 +0.00011266336187471834 60553:60553 +0.00011266336187471834 57932:57932 +0.00011266336187471834 56515:56515 +0.00011266336187471834 34025:34025 +0.00011266336187471834 59676:59676 +0.00011266336187471834 57619:57619 +0.00011266336187471834 55733:55733 +0.00011266336187471834 34130:34130 +0.00011266336187471834 34243:34243 +0.00011266336187471834 60897:60897 +0.00011266336187471834 59285:59285 +0.00011266336187471834 60053:60053 +0.00011266336187471834 59033:59033 +0.00011266336187471834 59772:59772 +0.00011266336187471834 34683:34683 +0.00011266336187471834 59356:59356 +0.00011266336187471834 32779:32779 +0.00011266336187471834 58817:58817 +0.00011266336187471834 59618:59618 +0.00011266336187471834 58674:58674 +0.00011266336187471834 59096:59096 +0.00011266336187471834 33589:33589 +0.00011266336187471834 33518:33518 +0.00011266336187471834 60077:60077 +0.00011266336187471834 56601:56601 +0.00011266336187471834 55886:55886 +0.00011266336187471834 35517:35517 +0.00011266336187471834 35427:35427 +0.00011266336187471834 55666:55666 +0.00011266336187471834 59418:59418 +0.00011266336187471834 56337:56337 +0.00011266336187471834 56022:56022 +0.00011266336187471834 34624:34624 +0.00011266336187471834 59923:59923 +0.00011266336187471834 57441:57441 +0.00011266336187471834 59819:59819 +0.00011266336187471834 35477:35477 +0.00011266336187471834 58381:58381 +0.00011266336187471834 57140:57140 +0.00011266336187471834 59592:59592 +0.00011266336187471834 57963:57963 +0.00011266336187471834 34045:34045 +0.00011266336187471834 33779:33779 +0.00011266336187471834 57651:57651 +0.00011266336187471834 58222:58222 +0.00011266336187471834 60986:60986 +0.00011266336187471834 56785:56785 +0.00011266336187471834 60623:60623 +0.00011266336187471834 59113:59113 +0.00011266336187471834 35091:35091 +0.00011266336187471834 33538:33538 +0.00011266336187471834 56363:56363 +0.00011266336187471834 55984:55984 +0.00011266336187471834 60964:60964 +0.00011266336187471834 33158:33158 +0.00011266336187471834 59085:59085 +0.00011266336187471834 35128:35128 +0.00011266336187471834 32857:32857 +0.00011266336187471834 58263:58263 +0.00011266336187471834 34693:34693 +0.00011266336187471834 60879:60879 +0.00011266336187471834 58576:58576 +0.00011266336187471834 56365:56365 +0.00011266336187471834 58324:58324 +0.00011266336187471834 34401:34401 +0.00011266336187471834 59947:59947 +0.00011266336187471834 32929:32929 +0.00011266336187471834 59976:59976 +0.00011266336187471834 59379:59379 +0.00011266336187471834 57218:57218 +0.00011266336187471834 57940:57940 +0.00011266336187471834 56034:56034 +0.00011266336187471834 34425:34425 +0.00011266336187471834 34742:34742 +0.00011266336187471834 33727:33727 +0.00011266336187471834 60378:60378 +0.00011266336187471834 59180:59180 +0.00011266336187471834 60256:60256 +0.00011266336187471834 34497:34497 +0.00011266336187471834 34360:34360 +0.00011266336187471834 60969:60969 +0.00011266336187471834 58385:58385 +0.00011266336187471834 57910:57910 +0.00011266336187471834 56204:56204 +0.00011266336187471834 58355:58355 +0.00011266336187471834 56111:56111 +0.00011266336187471834 33897:33897 +0.00011266336187471834 57027:57027 +0.00011266336187471834 33908:33908 +0.00011266336187471834 60071:60071 +0.00011266336187471834 59561:59561 +0.00011266336187471834 60141:60141 +0.00011266336187471834 35470:35470 +0.00011266336187471834 56405:56405 +0.00011266336187471834 60212:60212 +0.00011266336187471834 58114:58114 +0.00011266336187471834 57220:57220 +0.00011266336187471834 55990:55990 +0.00011266336187471834 33814:33814 +0.00011266336187471834 60267:60267 +0.00011266336187471834 34330:34330 +0.00011266336187471834 58644:58644 +0.00011266336187471834 34451:34451 +0.00011266336187471834 60977:60977 +0.00011266336187471834 59920:59920 +0.00011266336187471834 55736:55736 +0.00011266336187471834 34906:34906 +0.00011266336187471834 59985:59985 +0.00011266336187471834 57255:57255 +0.00011266336187471834 60001:60001 +0.00011266336187471834 35530:35530 +0.00011266336187471834 34509:34509 +0.00011266336187471834 57025:57025 +0.00011266336187471834 34005:34005 +0.00011266336187471834 35304:35304 +0.00011266336187471834 56068:56068 +0.00011266336187471834 58631:58631 +0.00011266336187471834 56837:56837 +0.00011266336187471834 57454:57454 +0.00011266336187471834 34019:34019 +0.00011266336187471834 35355:35355 +0.00011266336187471834 60459:60459 +0.00011266336187471834 58655:58655 +0.00011266336187471834 57558:57558 +0.00011266336187471834 56599:56599 +0.00011266336187471834 34024:34024 +0.00011266336187471834 34239:34239 +0.00011266336187471834 55755:55755 +0.00011266336187471834 56592:56592 +0.00011266336187471834 32988:32988 +0.00011266336187471834 57919:57919 +0.00011266336187471834 59369:59369 +0.00011266336187471834 58908:58908 +0.00011266336187471834 57779:57779 +0.00011266336187471834 34886:34886 +0.00011266336187471834 60262:60262 +0.00011266336187471834 34429:34429 +0.00011266336187471834 34338:34338 +0.00011266336187471834 59387:59387 +0.00011266336187471834 59125:59125 +0.00011266336187471834 57126:57126 +0.00011266336187471834 60065:60065 +0.00011266336187471834 57596:57596 +0.00011266336187471834 34890:34890 +0.00011266336187471834 58100:58100 +0.00011266336187471834 57114:57114 +0.00011266336187471834 34737:34737 +0.00011266336187471834 34613:34613 +0.00011266336187471834 60410:60410 +0.00011266336187471834 60108:60108 +0.00011266336187471834 34752:34752 +0.00011266336187471834 56550:56550 +0.00011266336187471834 32915:32915 +0.00011266336187471834 58151:58151 +0.00011266336187471834 56408:56408 +0.00011266336187471834 58322:58322 +0.00011266336187471834 58250:58250 +0.00011266336187471834 58269:58269 +0.00011266336187471834 35054:35054 +0.00011266336187471834 34893:34893 +0.00011266336187471834 34299:34299 +0.00011266336187471834 34281:34281 +0.00011266336187471834 33123:33123 +0.00011266336187471834 60058:60058 +0.00011266336187471834 56367:56367 +0.00011266336187471834 57186:57186 +0.00011266336187471834 59835:59835 +0.00011266336187471834 56299:56299 +0.00011266336187471834 58534:58534 +0.00011266336187471834 55650:55650 +0.00011266336187471834 32790:32790 +0.00011266336187471834 58718:58718 +0.00011266336187471834 58551:58551 +0.00011266336187471834 56526:56526 +0.00011266336187471834 56033:56033 +0.00011266336187471834 57354:57354 +0.00011266336187471834 56839:56839 +0.00011266336187471834 58995:58995 +0.00011266336187471834 58707:58707 +0.00011266336187471834 57670:57670 +0.00011266336187471834 58701:58701 +0.00011266336187471834 58493:58493 +0.00011266336187471834 34567:34567 +0.00011266336187471834 33391:33391 +0.00011266336187471834 59683:59683 +0.00011266336187471834 60912:60912 +0.00011266336187471834 55856:55856 +0.00011266336187471834 60370:60370 +0.00011266336187471834 34775:34775 +0.00011266336187471834 60307:60307 +0.00011266336187471834 56361:56361 +0.00011266336187471834 33946:33946 +0.00011266336187471834 57970:57970 +0.00011266336187471834 56791:56791 +0.00011266336187471834 35006:35006 +0.00011266336187471834 34358:34358 +0.00011266336187471834 58979:58979 +0.00011266336187471834 55764:55764 +0.00011266336187471834 34163:34163 +0.00011266336187471834 58687:58687 +0.00011266336187471834 57982:57982 +0.00011266336187471834 33499:33499 +0.00011266336187471834 32937:32937 +0.00011266336187471834 33648:33648 +0.00011266336187471834 33482:33482 +0.00011266336187471834 56528:56528 +0.00011266336187471834 35357:35357 +0.00011266336187471834 57587:57587 +0.00011266336187471834 35438:35438 +0.00011266336187471834 57090:57090 +0.00011266336187471834 56324:56324 +0.00011266336187471834 56279:56279 +0.00011266336187471834 33573:33573 +0.00011266336187471834 58652:58652 +0.00011266336187471834 60298:60298 +0.00011266336187471834 58596:58596 +0.00011266336187471834 58386:58386 +0.00011266336187471834 58098:58098 +0.00011266336187471834 56991:56991 +0.00011266336187471834 60586:60586 +0.00011266336187471834 60306:60306 +0.00011266336187471834 57403:57403 +0.00011266336187471834 56535:56535 +0.00011266336187471834 56944:56944 +0.00011266336187471834 60349:60349 +0.00011266336187471834 34986:34986 +0.00011266336187471834 32835:32835 +0.00011266336187471834 59874:59874 +0.00011266336187471834 57069:57069 +0.00011266336187471834 58028:58028 +0.00011266336187471834 59725:59725 +0.00011266336187471834 58621:58621 +0.00011266336187471834 58021:58021 +0.00011266336187471834 33165:33165 +0.00011266336187471834 59136:59136 +0.00011266336187471834 60939:60939 +0.00011266336187471834 56234:56234 +0.00011266336187471834 35533:35533 +0.00011266336187471834 34424:34424 +0.00011266336187471834 56216:56216 +0.00011266336187471834 35300:35300 +0.00011266336187471834 60249:60249 +0.00011266336187471834 33823:33823 +0.00011266336187471834 59321:59321 +0.00011266336187471834 39732:39732 +0.00011266336187471834 33916:33916 +0.00011266336187471834 58749:58749 +0.00011266336187471834 57217:57217 +0.00011266336187471834 34435:34435 +0.00011266336187471834 33945:33945 +0.00011266336187471834 56733:56733 +0.00011266336187471834 56377:56377 +0.00011266336187471834 58458:58458 +0.00011266336187471834 32968:32968 +0.00011266336187471834 33795:33795 +0.00011266336187471834 33537:33537 +0.00011266336187471834 57798:57798 +0.00011266336187471834 57009:57009 +0.00011266336187471834 59615:59615 +0.00011266336187471834 34837:34837 +0.00011266336187471834 58889:58889 +0.00011266336187471834 34710:34710 +0.00011266336187471834 32887:32887 +0.00011266336187471834 58999:58999 +0.00011266336187471834 57502:57502 +0.00011266336187471834 57312:57312 +0.00011266336187471834 57113:57113 +0.00011266336187471834 56827:56827 +0.00011266336187471834 58846:58846 +0.00011266336187471834 58439:58439 +0.00011266336187471834 34962:34962 +0.00011266336187471834 60886:60886 +0.00011266336187471834 60072:60072 +0.00011266336187471834 59364:59364 +0.00011266336187471834 56533:56533 +0.00011266336187471834 33271:33271 +0.00011266336187471834 56435:56435 +0.00011266336187471834 33866:33866 +0.00011266336187471834 58617:58617 +0.00011266336187471834 58555:58555 +0.00011266336187471834 34550:34550 +0.00011266336187471834 33246:33246 +0.00011266336187471834 33978:33978 +0.00011266336187471834 57359:57359 +0.00011266336187471834 35476:35476 +0.00011266336187471834 57153:57153 +0.00011266336187471834 55774:55774 +0.00011266336187471834 60495:60495 +0.00011266336187471834 55656:55656 +0.00011266336187471834 35406:35406 +0.00011266336187471834 57475:57475 +0.00011266336187471834 58550:58550 +0.00011266336187471834 58376:58376 +0.00011266336187471834 55810:55810 +0.00011266336187471834 34615:34615 +0.00011266336187471834 59509:59509 +0.00011266336187471834 58275:58275 +0.00011266336187471834 56364:56364 +0.00011266336187471834 60541:60541 +0.00011266336187471834 58828:58828 +0.00011266336187471834 35311:35311 +0.00011266336187471834 59189:59189 +0.00011266336187471834 58087:58087 +0.00011266336187471834 33689:33689 +0.00011266336187471834 58779:58779 +0.00011266336187471834 32789:32789 +0.00011266336187471834 59619:59619 +0.00011266336187471834 55808:55808 +0.00011266336187471834 34988:34988 +0.00011266336187471834 34533:34533 +0.00011266336187471834 59013:59013 +0.00011266336187471834 56347:56347 +0.00011266336187471834 33778:33778 +0.00011266336187471834 33490:33490 +0.00011266336187471834 57869:57869 +0.00011266336187471834 58190:58190 +0.00011266336187471834 55999:55999 +0.00011266336187471834 56252:56252 +0.00011266336187471834 34427:34427 +0.00011266336187471834 60075:60075 +0.00011266336187471834 56906:56906 +0.00011266336187471834 60580:60580 +0.00011266336187471834 35317:35317 +0.00011266336187471834 57901:57901 +0.00011266336187471834 58317:58317 +0.00011266336187471834 58070:58070 +0.00011266336187471834 33776:33776 +0.00011266336187471834 60351:60351 +0.00011266336187471834 59791:59791 +0.00011266336187471834 58239:58239 +0.00011266336187471834 57584:57584 +0.00011266336187471834 58808:58808 +0.00011266336187471834 58139:58139 +0.00011266336187471834 57566:57566 +0.00011266336187471834 59901:59901 +0.00011266336187471834 59079:59079 +0.00011266336187471834 57693:57693 +0.00011266336187471834 32931:32931 +0.00011266336187471834 57740:57740 +0.00011266336187471834 59404:59404 +0.00011266336187471834 35055:35055 +0.00011266336187471834 33867:33867 +0.00011266336187471834 58876:58876 +0.00011266336187471834 33184:33184 +0.00011266336187471834 56171:56171 +0.00011266336187471834 57606:57606 +0.00011266336187471834 35434:35434 +0.00011266336187471834 56362:56362 +0.00011266336187471834 60102:60102 +0.00011266336187471834 58123:58123 +0.00011266336187471834 55964:55964 +0.00011266336187471834 35474:35474 +0.00011266336187471834 56555:56555 +0.00011266336187471834 57603:57603 +0.00011266336187471834 55657:55657 +0.00011266336187471834 33794:33794 +0.00011266336187471834 33517:33517 +0.00011266336187471834 33044:33044 +0.00011266336187471834 58781:58781 +0.00011266336187471834 56838:56838 +0.00011266336187471834 33346:33346 +0.00011266336187471834 60429:60429 +0.00011266336187471834 58232:58232 +0.00011266336187471834 55672:55672 +0.00011266336187471834 56269:56269 +0.00011266336187471834 59047:59047 +0.00011266336187471834 57550:57550 +0.00011266336187471834 34215:34215 +0.00011266336187471834 34054:34054 +0.00011266336187471834 35286:35286 +0.00011266336187471834 56970:56970 +0.00011266336187471834 56802:56802 +0.00011266336187471834 56191:56191 +0.00011266336187471834 58838:58838 +0.00011266336187471834 57408:57408 +0.00011266336187471834 58559:58559 +0.00011266336187471834 59394:59394 +0.00011266336187471834 58969:58969 +0.00011266336187471834 59969:59969 +0.00011266336187471834 58179:58179 +0.00011266336187471834 34779:34779 +0.00011266336187471834 34637:34637 +0.00011266336187471834 33706:33706 +0.00011266336187471834 34395:34395 +0.00011266336187471834 60342:60342 +0.00011266336187471834 58912:58912 +0.00011266336187471834 60449:60449 +0.00011266336187471834 60443:60443 +0.00011266336187471834 55969:55969 +0.00011266336187471834 59294:59294 +0.00011266336187471834 58041:58041 +0.00011266336187471834 57844:57844 +0.00011266336187471834 55717:55717 +0.00011266336187471834 55907:55907 +0.00011266336187471834 32820:32820 +0.00011266336187471834 34178:34178 +0.00011266336187471834 33543:33543 +0.00011266336187471834 35374:35374 +0.00011266336187471834 34619:34619 +0.00011266336187471834 55994:55994 +0.00011266336187471834 60562:60562 +0.00011266336187471834 58169:58169 +0.00011266336187471834 57235:57235 +0.00011266336187471834 60396:60396 +0.00011266336187471834 59812:59812 +0.00011266336187471834 59551:59551 +0.00011266336187471834 32830:32830 +0.00011266336187471834 57735:57735 +0.00011266336187471834 57655:57655 +0.00011266336187471834 33109:33109 +0.00011266336187471834 55634:55634 +0.00011266336187471834 58648:58648 +0.00011266336187471834 58352:58352 +0.00011266336187471834 35111:35111 +0.00011266336187471834 33613:33613 +0.00011266336187471834 59514:59514 +0.00011266336187471834 55621:55621 +0.00011266336187471834 60218:60218 +0.00011266336187471834 57351:57351 +0.00011266336187471834 60944:60944 +0.00011266336187471834 34478:34478 +0.00011266336187471834 60213:60213 +0.00011266336187471834 59591:59591 +0.00011266336187471834 57654:57654 +0.00011266336187471834 59402:59402 +0.00011266336187471834 58318:58318 +0.00011266336187471834 58714:58714 +0.00011266336187471834 32842:32842 +0.00011266336187471834 57297:57297 +0.00011266336187471834 34939:34939 +0.00011266336187471834 34907:34907 +0.00011266336187471834 57510:57510 +0.00011266336187471834 34483:34483 +0.00011266336187471834 32992:32992 +0.00011266336187471834 56415:56415 +0.00011266336187471834 60767:60767 +0.00011266336187471834 33195:33195 +0.00011266336187471834 34353:34353 +0.00011266336187471834 55959:55959 +0.00011266336187471834 35270:35270 +0.00011266336187471834 35221:35221 +0.00011266336187471834 57878:57878 +0.00011266336187471834 57314:57314 +0.00011266336187471834 34177:34177 +0.00011266336187471834 33504:33504 +0.00011266336187471834 35526:35526 +0.00011266336187471834 33766:33766 +0.00011266336187471834 56958:56958 +0.00011266336187471834 32917:32917 +0.00011266336187471834 59672:59672 +0.00011266336187471834 58998:58998 +0.00011266336187471834 35274:35274 +0.00011266336187471834 34653:34653 +0.00011266336187471834 32947:32947 +0.00011266336187471834 60441:60441 +0.00011266336187471834 33153:33153 +0.00011266336187471834 57841:57841 +0.00011266336187471834 58795:58795 +0.00011266336187471834 55830:55830 +0.00011266336187471834 34650:34650 +0.00011266336187471834 58878:58878 +0.00011266336187471834 58448:58448 +0.00011266336187471834 60367:60367 +0.00011266336187471834 59717:59717 +0.00011266336187471834 58903:58903 +0.00011266336187471834 57455:57455 +0.00011266336187471834 35018:35018 +0.00011266336187471834 58590:58590 +0.00011266336187471834 32885:32885 +0.00011266336187471834 57476:57476 +0.00011266336187471834 34008:34008 +0.00011266336187471834 60598:60598 +0.00011266336187471834 57848:57848 +0.00011266336187471834 56638:56638 +0.00011266336187471834 56439:56439 +0.00011266336187471834 34469:34469 +0.00011266336187471834 60947:60947 +0.00011266336187471834 58479:58479 +0.00011266336187471834 57956:57956 +0.00011266336187471834 33968:33968 +0.00011266336187471834 58801:58801 +0.00011266336187471834 57199:57199 +0.00011266336187471834 34829:34829 +0.00011266336187471834 59638:59638 +0.00011266336187471834 59577:59577 +0.00011266336187471834 57667:57667 +0.00011266336187471834 57513:57513 +0.00011266336187471834 55655:55655 +0.00011266336187471834 33477:33477 +0.00011266336187471834 32781:32781 +0.00011266336187471834 35539:35539 +0.00011266336187471834 59913:59913 +0.00011266336187471834 34109:34109 +0.00011266336187471834 33449:33449 +0.00011266336187471834 34768:34768 +0.00011266336187471834 33264:33264 +0.00011266336187471834 59348:59348 +0.00011266336187471834 33240:33240 +0.00011266336187471834 32944:32944 +0.00011266336187471834 60257:60257 +0.00011266336187471834 33974:33974 +0.00011266336187471834 33784:33784 +0.00011266336187471834 34617:34617 +0.00011266336187471834 34194:34194 +0.00011266336187471834 35271:35271 +0.00011266336187471834 56085:56085 +0.00011266336187471834 34501:34501 +0.00011266336187471834 33475:33475 +0.00011266336187471834 59567:59567 +0.00011266336187471834 55881:55881 +0.00011266336187471834 59409:59409 +0.00011266336187471834 59374:59374 +0.00011266336187471834 34587:34587 +0.00011266336187471834 57291:57291 +0.00011266336187471834 60397:60397 +0.00011266336187471834 56284:56284 +0.00011266336187471834 59024:59024 +0.00011266336187471834 57727:57727 +0.00011266336187471834 34853:34853 +0.00011266336187471834 57870:57870 +0.00011266336187471834 57845:57845 +0.00011266336187471834 59604:59604 +0.00011266336187471834 57542:57542 +0.00011266336187471834 60650:60650 +0.00011266336187471834 33426:33426 +0.00011266336187471834 59878:59878 +0.00011266336187471834 59670:59670 +0.00011266336187471834 32950:32950 +0.00011266336187471834 33252:33252 +0.00011266336187471834 33427:33427 +0.00011266336187471834 57461:57461 +0.00011266336187471834 60091:60091 +0.00011266336187471834 35021:35021 +0.00011266336187471834 57068:57068 +0.00011266336187471834 57141:57141 +0.00011266336187471834 55961:55961 +0.00011266336187471834 60060:60060 +0.00011266336187471834 57127:57127 +0.00011266336187471834 59195:59195 +0.00011266336187471834 60835:60835 +0.00011266336187471834 58475:58475 +0.00011266336187471834 59664:59664 +0.00011266336187471834 33202:33202 +0.00011266336187471834 60074:60074 +0.00011266336187471834 33787:33787 +0.00011266336187471834 35134:35134 +0.00011266336187471834 55816:55816 +0.00011266336187471834 33915:33915 +0.00011266336187471834 59839:59839 +0.00011266336187471834 34817:34817 +0.00011266336187471834 55892:55892 +0.00011266336187471834 58035:58035 +0.00011266336187471834 56695:56695 +0.00011266336187471834 34723:34723 +0.00011266336187471834 34461:34461 +0.00011266336187471834 56941:56941 +0.00011266336187471834 55941:55941 +0.00011266336187471834 34664:34664 +0.00011266336187471834 59669:59669 +0.00011266336187471834 57562:57562 +0.00011266336187471834 33340:33340 +0.00011266336187471834 59686:59686 +0.00011266336187471834 33515:33515 +0.00011266336187471834 56814:56814 +0.00011266336187471834 59678:59678 +0.00011266336187471834 60439:60439 +0.00011266336187471834 56627:56627 +0.00011266336187471834 58859:58859 +0.00011266336187471834 34245:34245 +0.00011266336187471834 58279:58279 +0.00011266336187471834 33638:33638 +0.00011266336187471834 33136:33136 +0.00011266336187471834 33661:33661 +0.00011266336187471834 58523:58523 +0.00011266336187471834 56677:56677 +0.00011266336187471834 58981:58981 +0.00011266336187471834 58231:58231 +0.00011266336187471834 56691:56691 +0.00011266336187471834 60985:60985 +0.00011266336187471834 58578:58578 +0.00011266336187471834 56203:56203 +0.00011266336187471834 58930:58930 +0.00011266336187471834 56536:56536 +0.00011266336187471834 34816:34816 +0.00011266336187471834 33128:33128 +0.00011266336187471834 60830:60830 +0.00011266336187471834 57915:57915 +0.00011266336187471834 58608:58608 +0.00011266336187471834 55703:55703 +0.00011266336187471834 57883:57883 +0.00011266336187471834 56746:56746 +0.00011266336187471834 35353:35353 +0.00011266336187471834 59802:59802 +0.00011266336187471834 32987:32987 +0.00011266336187471834 34841:34841 +0.00011266336187471834 60005:60005 +0.00011266336187471834 57425:57425 +0.00011266336187471834 59218:59218 +0.00011266336187471834 56784:56784 +0.00011266336187471834 60797:60797 +0.00011266336187471834 56513:56513 +0.00011266336187471834 59397:59397 +0.00011266336187471834 56018:56018 +0.00011266336187471834 33598:33598 +0.00011266336187471834 59883:59883 +0.00011266336187471834 56438:56438 +0.00011266336187471834 35369:35369 +0.00011266336187471834 34620:34620 +0.00011266336187471834 59716:59716 +0.00011266336187471834 34265:34265 +0.00011266336187471834 32817:32817 +0.00011266336187471834 56319:56319 +0.00011266336187471834 35520:35520 +0.00011266336187471834 55807:55807 +0.00011266336187471834 34371:34371 +0.00011266336187471834 56466:56466 +0.00011266336187471834 34987:34987 +0.00011266336187471834 58036:58036 +0.00011266336187471834 33842:33842 +0.00011266336187471834 33378:33378 +0.00011266336187471834 34406:34406 +0.00011266336187471834 33121:33121 +0.00011266336187471834 35389:35389 +0.00011266336187471834 34368:34368 +0.00011266336187471834 33476:33476 +0.00011266336187471834 58943:58943 +0.00011266336187471834 59755:59755 +0.00011266336187471834 59471:59471 +0.00011266336187471834 34147:34147 +0.00011266336187471834 59628:59628 +0.00011266336187471834 55858:55858 +0.00011266336187471834 57706:57706 +0.00011266336187471834 56864:56864 +0.00011266336187471834 33583:33583 +0.00011266336187471834 59927:59927 +0.00011266336187471834 60134:60134 +0.00011266336187471834 59253:59253 +0.00011266336187471834 58568:58568 +0.00011266336187471834 34333:34333 +0.00011266336187471834 55715:55715 +0.00011266336187471834 33066:33066 +0.00011266336187471834 59460:59460 +0.00011266336187471834 59290:59290 +0.00011266336187471834 60113:60113 +0.00011266336187471834 57807:57807 +0.00011266336187471834 34105:34105 +0.00011266336187471834 35034:35034 +0.00011266336187471834 34141:34141 +0.00011266336187471834 60570:60570 +0.00011266336187471834 35332:35332 +0.00011266336187471834 33714:33714 +0.00011266336187471834 57205:57205 +0.00011266336187471834 33788:33788 +0.00011266336187471834 60493:60493 +0.00011266336187471834 59610:59610 +0.00011266336187471834 57253:57253 +0.00011266336187471834 56946:56946 +0.00011266336187471834 33146:33146 +0.00011266336187471834 60247:60247 +0.00011266336187471834 59803:59803 +0.00011266336187471834 56477:56477 +0.00011266336187471834 55739:55739 +0.00011266336187471834 35080:35080 +0.00011266336187471834 58953:58953 +0.00011266336187471834 56444:56444 +0.00011266336187471834 35188:35188 +0.00011266336187471834 35367:35367 +0.00011266336187471834 58293:58293 +0.00011266336187471834 58104:58104 +0.00011266336187471834 58235:58235 +0.00011266336187471834 57534:57534 +0.00011266336187471834 60987:60987 +0.00011266336187471834 57417:57417 +0.00011266336187471834 56788:56788 +0.00011266336187471834 57311:57311 +0.00011266336187471834 55867:55867 +0.00011266336187471834 33987:33987 +0.00011266336187471834 59930:59930 +0.00011266336187471834 58965:58965 +0.00011266336187471834 33273:33273 +0.00011266336187471834 60007:60007 +0.00011266336187471834 55955:55955 +0.00011266336187471834 35370:35370 +0.00011266336187471834 33400:33400 +0.00011266336187471834 60617:60617 +0.00011266336187471834 60453:60453 +0.00011266336187471834 59688:59688 +0.00011266336187471834 56845:56845 +0.00011266336187471834 58454:58454 +0.00011266336187471834 35103:35103 +0.00011266336187471834 58944:58944 +0.00011266336187471834 56055:56055 +0.00011266336187471834 59156:59156 +0.00011266336187471834 59999:59999 +0.00011266336187471834 60775:60775 +0.00011266336187471834 56818:56818 +0.00011266336187471834 56120:56120 +0.00011266336187471834 57405:57405 +0.00011266336187471834 56756:56756 +0.00011266336187471834 60854:60854 +0.00011266336187471834 60175:60175 +0.00011266336187471834 34437:34437 +0.00011266336187471834 33773:33773 +0.00011266336187471834 57794:57794 +0.00011266336187471834 57555:57555 +0.00011266336187471834 59132:59132 +0.00011266336187471834 34246:34246 +0.00011266336187471834 32838:32838 +0.00011266336187471834 56436:56436 +0.00011266336187471834 58241:58241 +0.00011266336187471834 58005:58005 +0.00011266336187471834 33406:33406 +0.00011266336187471834 35245:35245 +0.00011266336187471834 34013:34013 +0.00011266336187471834 59034:59034 +0.00011266336187471834 34796:34796 +0.00011266336187471834 58444:58444 +0.00011266336187471834 35345:35345 +0.00011266336187471834 32859:32859 +0.00011266336187471834 32791:32791 +0.00011266336187471834 60962:60962 +0.00011266336187471834 35556:35556 +0.00011266336187471834 60145:60145 +0.00011266336187471834 58985:58985 +0.00011266336187471834 58741:58741 +0.00011266336187471834 58051:58051 +0.00011266336187471834 32925:32925 +0.00011266336187471834 60958:60958 +0.00011266336187471834 59128:59128 +0.00011266336187471834 59981:59981 +0.00011266336187471834 58787:58787 +0.00011266336187471834 57594:57594 +0.00011266336187471834 56735:56735 +0.00011266336187471834 57826:57826 +0.00011266336187471834 56259:56259 +0.00011266336187471834 35155:35155 +0.00011266336187471834 58814:58814 +0.00011266336187471834 35454:35454 +0.00011266336187471834 56144:56144 +0.00011266336187471834 56504:56504 +0.00011266336187471834 60187:60187 +0.00011266336187471834 58609:58609 +0.00011266336187471834 58406:58406 +0.00011266336187471834 56866:56866 +0.00011266336187471834 58900:58900 +0.00011266336187471834 34918:34918 +0.00011266336187471834 33928:33928 +0.00011266336187471834 60730:60730 +0.00011266336187471834 60631:60631 +0.00011266336187471834 58013:58013 +0.00011266336187471834 56510:56510 +0.00011266336187471834 56859:56859 +0.00011266336187471834 58785:58785 +0.00011266336187471834 57836:57836 +0.00011266336187471834 34580:34580 +0.00011266336187471834 58353:58353 +0.00011266336187471834 60953:60953 +0.00011266336187471834 57646:57646 +0.00011266336187471834 57051:57051 +0.00011266336187471834 60976:60976 +0.00011266336187471834 58366:58366 +0.00011266336187471834 56931:56931 +0.00011266336187471834 33617:33617 +0.00011266336187471834 56413:56413 +0.00011266336187471834 32912:32912 +0.00011266336187471834 59009:59009 +0.00011266336187471834 33261:33261 +0.00011266336187471834 57929:57929 +0.00011266336187471834 56565:56565 +0.00011266336187471834 34277:34277 +0.00011266336187471834 60706:60706 +0.00011266336187471834 56220:56220 +0.00011266336187471834 34114:34114 +0.00011266336187471834 33343:33343 +0.00011266336187471834 56822:56822 +0.00011266336187471834 34428:34428 +0.00011266336187471834 33528:33528 +0.00011266336187471834 59475:59475 +0.00011266336187471834 55838:55838 +0.00011266336187471834 35092:35092 +0.00011266336187471834 56517:56517 +0.00011266336187471834 56308:56308 +0.00011266336187471834 33016:33016 +0.00011266336187471834 56948:56948 +0.00011266336187471834 35465:35465 +0.00011266336187471834 60509:60509 +0.00011266336187471834 60710:60710 +0.00011266336187471834 56164:56164 +0.00011266336187471834 56194:56194 +0.00011266336187471834 57810:57810 +0.00011266336187471834 55977:55977 +0.00011266336187471834 59325:59325 +0.00011266336187471834 58452:58452 +0.00011266336187471834 56918:56918 +0.00011266336187471834 56423:56423 +0.00011266336187471834 55948:55948 +0.00011266336187471834 55793:55793 +0.00011266336187471834 60140:60140 +0.00011266336187471834 59267:59267 +0.00011266336187471834 58993:58993 +0.00011266336187471834 58788:58788 +0.00011266336187471834 57726:57726 +0.00011266336187471834 56600:56600 +0.00011266336187471834 35112:35112 +0.00011266336187471834 60442:60442 +0.00011266336187471834 34164:34164 +0.00011266336187471834 60176:60176 +0.00011266336187471834 33935:33935 +0.00011266336187471834 33859:33859 +0.00011266336187471834 35302:35302 +0.00011266336187471834 60584:60584 +0.00011266336187471834 59318:59318 +0.00011266336187471834 34376:34376 +0.00011266336187471834 34325:34325 +0.00011266336187471834 59449:59449 +0.00011266336187471834 58984:58984 +0.00011266336187471834 57449:57449 +0.00011266336187471834 59448:59448 +0.00011266336187471834 60066:60066 +0.00011266336187471834 59466:59466 +0.00011266336187471834 60653:60653 +0.00011266336187471834 33371:33371 +0.00011266336187471834 35488:35488 +0.00011266336187471834 58647:58647 +0.00011266336187471834 57503:57503 +0.00011266336187471834 57586:57586 +0.00011266336187471834 56969:56969 +0.00011266336187471834 34234:34234 +0.00011266336187471834 33494:33494 +0.00011266336187471834 60174:60174 +0.00011266336187471834 34903:34903 +0.00011266336187471834 34166:34166 +0.00011266336187471834 59616:59616 +0.00011266336187471834 60735:60735 +0.00011266336187471834 57585:57585 +0.00011266336187471834 56141:56141 +0.00011266336187471834 35272:35272 +0.00011266336187471834 35219:35219 +0.00011266336187471834 34860:34860 +0.00011266336187471834 60228:60228 +0.00011266336187471834 56593:56593 +0.00011266336187471834 55731:55731 +0.00011266336187471834 60982:60982 +0.00011266336187471834 56452:56452 +0.00011266336187471834 35269:35269 +0.00011266336187471834 33336:33336 +0.00011266336187471834 59444:59444 +0.00011266336187471834 33937:33937 +0.00011266336187471834 33368:33368 +0.00011266336187471834 60758:60758 +0.00011266336187471834 33440:33440 +0.00011266336187471834 34188:34188 +0.00011266336187471834 56911:56911 +0.00011266336187471834 34974:34974 +0.00011266336187471834 60817:60817 +0.00011266336187471834 59232:59232 +0.00011266336187471834 34747:34747 +0.00011266336187471834 32958:32958 +0.00011266336187471834 59105:59105 +0.00011266336187471834 60152:60152 +0.00011266336187471834 57202:57202 +0.00011266336187471834 34385:34385 +0.00011266336187471834 60852:60852 +0.00011266336187471834 35554:35554 +0.00011266336187471834 32772:32772 +0.00011266336187471834 34222:34222 +0.00011266336187471834 60198:60198 +0.00011266336187471834 58016:58016 +0.00011266336187471834 33159:33159 +0.00011266336187471834 59257:59257 +0.00011266336187471834 58290:58290 +0.00011266336187471834 57486:57486 +0.00011266336187471834 34911:34911 +0.00011266336187471834 33951:33951 +0.00011266336187471834 33806:33806 +0.00011266336187471834 59520:59520 +0.00011266336187471834 58131:58131 +0.00011266336187471834 56841:56841 +0.00011266336187471834 33715:33715 +0.00011266336187471834 55966:55966 +0.00011266336187471834 59898:59898 +0.00011266336187471834 56093:56093 +0.00011266336187471834 59633:59633 +0.00011266336187471834 58877:58877 +0.00011266336187471834 33000:33000 +0.00011266336187471834 33529:33529 +0.00011266336187471834 58288:58288 +0.00011266336187471834 57707:57707 +0.00011266336187471834 34916:34916 +0.00011266336187471834 58511:58511 +0.00011266336187471834 56748:56748 +0.00011266336187471834 33178:33178 +0.00011266336187471834 33107:33107 +0.00011266336187471834 60920:60920 +0.00011266336187471834 58599:58599 +0.00011266336187471834 34922:34922 +0.00011266336187471834 58666:58666 +0.00011266336187471834 34990:34990 +0.00011266336187471834 33666:33666 +0.00011266336187471834 58720:58720 +0.00011266336187471834 60348:60348 +0.00011266336187471834 35068:35068 +0.00011266336187471834 35203:35203 +0.00011266336187471834 34323:34323 +0.00011266336187471834 58270:58270 +0.00011266336187471834 60968:60968 +0.00011266336187471834 57325:57325 +0.00011266336187471834 57193:57193 +0.00011266336187471834 56851:56851 +0.00011266336187471834 35368:35368 +0.00011266336187471834 58140:58140 +0.00011266336187471834 60337:60337 +0.00011266336187471834 59163:59163 +0.00011266336187471834 33276:33276 +0.00011266336187471834 34677:34677 +0.00011266336187471834 35551:35551 +0.00011266336187471834 32837:32837 +0.00011266336187471834 35303:35303 +0.00011266336187471834 55646:55646 +0.00011266336187471834 59854:59854 +0.00011266336187471834 59710:59710 +0.00011266336187471834 60806:60806 +0.00011266336187471834 34392:34392 +0.00011266336187471834 59480:59480 +0.00011266336187471834 34584:34584 +0.00011266336187471834 33561:33561 +0.00011266336187471834 59091:59091 +0.00011266336187471834 33115:33115 +0.00011266336187471834 57717:57717 +0.00011266336187471834 60560:60560 +0.00011266336187471834 60344:60344 +0.00011266336187471834 58885:58885 +0.00011266336187471834 56834:56834 +0.00011266336187471834 59244:59244 +0.00011266336187471834 56786:56786 +0.00011266336187471834 33895:33895 +0.00011266336187471834 56684:56684 +0.00011266336187471834 58604:58604 +0.00011266336187471834 60305:60305 +0.00011266336187471834 57897:57897 +0.00011266336187471834 59864:59864 +0.00011266336187471834 58209:58209 +0.00011266336187471834 55835:55835 +0.00011266336187471834 57944:57944 +0.00011266336187471834 57081:57081 +0.00011266336187471834 60234:60234 +0.00011266336187471834 57265:57265 +0.00011266336187471834 59271:59271 +0.00011266336187471834 59045:59045 +0.00011266336187471834 58135:58135 +0.00011266336187471834 55975:55975 +0.00011266336187471834 56307:56307 +0.00011266336187471834 59241:59241 +0.00011266336187471834 57840:57840 +0.00011266336187471834 34221:34221 +0.00011266336187471834 57888:57888 +0.00011266336187471834 57268:57268 +0.00011266336187471834 55686:55686 +0.00011266336187471834 60887:60887 +0.00011266336187471834 58592:58592 +0.00011266336187471834 57860:57860 +0.00011266336187471834 60666:60666 +0.00011266336187471834 55976:55976 +0.00011266336187471834 34882:34882 +0.00011266336187471834 58694:58694 +0.00011266336187471834 60543:60543 +0.00011266336187471834 58588:58588 +0.00011266336187471834 56868:56868 +0.00011266336187471834 57772:57772 +0.00011266336187471834 33151:33151 +0.00011266336187471834 34072:34072 +0.00011266336187471834 60049:60049 +0.00011266336187471834 56114:56114 +0.00011266336187471834 58778:58778 +0.00011266336187471834 57416:57416 +0.00011266336187471834 59225:59225 +0.00011266336187471834 58116:58116 +0.00011266336187471834 35218:35218 +0.00011266336187471834 34929:34929 +0.00011266336187471834 60240:60240 +0.00011266336187471834 60192:60192 +0.00011266336187471834 33972:33972 +0.00011266336187471834 56095:56095 +0.00011266336187471834 33090:33090 +0.00011266336187471834 60130:60130 +0.00011266336187471834 58747:58747 +0.00011266336187471834 59757:59757 +0.00011266336187471834 34115:34115 +0.00011266336187471834 34075:34075 +0.00011266336187471834 58413:58413 +0.00011266336187471834 58305:58305 +0.00011266336187471834 56538:56538 +0.00011266336187471834 34592:34592 +0.00011266336187471834 34278:34278 +0.00011266336187471834 60665:60665 +0.00011266336187471834 60531:60531 +0.00011266336187471834 60125:60125 +0.00011266336187471834 58730:58730 +0.00011266336187471834 33100:33100 +0.00011266336187471834 59731:59731 +0.00011266336187471834 56823:56823 +0.00011266336187471834 33251:33251 +0.00011266336187471834 56954:56954 +0.00011266336187471834 58660:58660 +0.00011266336187471834 55698:55698 +0.00011266336187471834 34721:34721 +0.00011266336187471834 60544:60544 +0.00011266336187471834 35060:35060 +0.00011266336187471834 60923:60923 +0.00011266336187471834 57857:57857 +0.00011266336187471834 33087:33087 +0.00011266336187471834 32936:32936 +0.00011266336187471834 58327:58327 +0.00011266336187471834 58346:58346 +0.00011266336187471834 58764:58764 +0.00011266336187471834 60600:60600 +0.00011266336187471834 33433:33433 +0.00011266336187471834 59498:59498 +0.00011266336187471834 59084:59084 +0.00011266336187471834 57756:57756 +0.00011266336187471834 33860:33860 +0.00011266336187471834 59936:59936 +0.00011266336187471834 57281:57281 +0.00011266336187471834 35327:35327 +0.00011266336187471834 34889:34889 +0.00011266336187471834 60391:60391 +0.00011266336187471834 33980:33980 +0.00011266336187471834 60610:60610 +0.00011266336187471834 57636:57636 +0.00011266336187471834 59621:59621 +0.00011266336187471834 34060:34060 +0.00011266336187471834 59072:59072 +0.00011266336187471834 57577:57577 +0.00011266336187471834 60177:60177 +0.00011266336187471834 56615:56615 +0.00011266336187471834 33225:33225 +0.00011266336187471834 58529:58529 +0.00011266336187471834 57865:57865 +0.00011266336187471834 34199:34199 +0.00011266336187471834 57933:57933 +0.00011266336187471834 57638:57638 +0.00011266336187471834 57699:57699 +0.00011266336187471834 34863:34863 +0.00011266336187471834 58962:58962 +0.00011266336187471834 55626:55626 +0.00011266336187471834 58491:58491 +0.00011266336187471834 56432:56432 +0.00011266336187471834 34951:34951 +0.00011266336187471834 59186:59186 +0.00011266336187471834 57778:57778 +0.00011266336187471834 35423:35423 +0.00011266336187471834 55820:55820 +0.00011266336187471834 60205:60205 +0.00011266336187471834 34080:34080 +0.00011266336187471834 35549:35549 +0.00011266336187471834 60382:60382 +0.00011266336187471834 59599:59599 +0.00011266336187471834 34855:34855 +0.00011266336187471834 33892:33892 +0.00011266336187471834 60898:60898 +0.00011266336187471834 57431:57431 +0.00011266336187471834 56098:56098 +0.00011266336187471834 59014:59014 +0.00011266336187471834 57317:57317 +0.00011266336187471834 56490:56490 +0.00011266336187471834 57559:57559 +0.00011266336187471834 58897:58897 +0.00011266336187471834 58014:58014 +0.00011266336187471834 58069:58069 +0.00011266336187471834 35455:35455 +0.00011266336187471834 56811:56811 +0.00011266336187471834 59721:59721 +0.00011266336187471834 33011:33011 +0.00011266336187471834 34688:34688 +0.00011266336187471834 56195:56195 +0.00011266336187471834 58226:58226 +0.00011266336187471834 35532:35532 +0.00011266336187471834 33920:33920 +0.00011266336187471834 58071:58071 +0.00011266336187471834 56752:56752 +0.00011266336187471834 60635:60635 +0.00011266336187471834 59396:59396 +0.00011266336187471834 55834:55834 +0.00011266336187471834 58615:58615 +0.00011266336187471834 56499:56499 +0.00011266336187471834 59263:59263 +0.00011266336187471834 56541:56541 +0.00011266336187471834 60831:60831 +0.00011266336187471834 33516:33516 +0.00011266336187471834 56561:56561 +0.00011266336187471834 59689:59689 +0.00011266336187471834 55848:55848 +0.00011266336187471834 59268:59268 +0.00011266336187471834 58034:58034 +0.00011266336187471834 56943:56943 +0.00011266336187471834 56429:56429 +0.00011266336187471834 57243:57243 +0.00011266336187471834 57722:57722 +0.00011266336187471834 58875:58875 +0.00011266336187471834 57207:57207 +0.00011266336187471834 35096:35096 +0.00011266336187471834 35002:35002 +0.00011266336187471834 34659:34659 +0.00011266336187471834 58941:58941 +0.00011266336187471834 57238:57238 +0.00011266336187471834 60739:60739 +0.00011266336187471834 58420:58420 +0.00011266336187471834 59439:59439 +0.00011266336187471834 60195:60195 +0.00011266336187471834 58004:58004 +0.00011266336187471834 57950:57950 +0.00011266336187471834 58059:58059 +0.00011266336187471834 56867:56867 +0.00011266336187471834 55629:55629 +0.00011266336187471834 56852:56852 +0.00011266336187471834 55832:55832 +0.00011266336187471834 59565:59565 +0.00011266336187471834 33802:33802 +0.00011266336187471834 58338:58338 +0.00011266336187471834 56762:56762 +0.00011266336187471834 34388:34388 +0.00011266336187471834 58457:58457 +0.00011266336187471834 34134:34134 +0.00011266336187471834 34499:34499 +0.00011266336187471834 59459:59459 +0.00011266336187471834 59005:59005 +0.00011266336187471834 56754:56754 +0.00011266336187471834 34430:34430 +0.00011266336187471834 35534:35534 +0.00011266336187471834 56325:56325 +0.00011266336187471834 34698:34698 +0.00011266336187471834 60112:60112 +0.00011266336187471834 58244:58244 +0.00011266336187471834 35343:35343 +0.00011266336187471834 34266:34266 +0.00011266336187471834 33696:33696 +0.00011266336187471834 55947:55947 +0.00011266336187471834 35479:35479 +0.00011266336187471834 56692:56692 +0.00011266336187471834 56500:56500 +0.00011266336187471834 33156:33156 +0.00011266336187471834 59818:59818 +0.00011266336187471834 58543:58543 +0.00011266336187471834 33558:33558 +0.00011266336187471834 34695:34695 +0.00011266336187471834 58281:58281 +0.00011266336187471834 58122:58122 +0.00011266336187471834 57006:57006 +0.00011266336187471834 35348:35348 +0.00011266336187471834 34419:34419 +0.00011266336187471834 60547:60547 +0.00011266336187471834 59422:59422 +0.00011266336187471834 57419:57419 +0.00011266336187471834 57809:57809 +0.00011266336187471834 57160:57160 +0.00011266336187471834 56419:56419 +0.00011266336187471834 59484:59484 +0.00011266336187471834 57435:57435 +0.00011266336187471834 60469:60469 +0.00011266336187471834 55683:55683 +0.00011266336187471834 60649:60649 +0.00011266336187471834 33383:33383 +0.00011266336187471834 59020:59020 +0.00011266336187471834 33411:33411 +0.00011266336187471834 33119:33119 +0.00011266336187471834 60016:60016 +0.00011266336187471834 58129:58129 +0.00011266336187471834 34991:34991 +0.00011266336187471834 59693:59693 +0.00011266336187471834 57557:57557 +0.00011266336187471834 56383:56383 +0.00011266336187471834 58607:58607 +0.00011266336187471834 59066:59066 +0.00011266336187471834 59555:59555 +0.00011266336187471834 56914:56914 +0.00011266336187471834 33732:33732 +0.00011266336187471834 33379:33379 +0.00011266336187471834 58642:58642 +0.00011266336187471834 57234:57234 +0.00011266336187471834 57752:57752 +0.00011266336187471834 58349:58349 +0.00011266336187471834 59658:59658 +0.00011266336187471834 59473:59473 +0.00011266336187471834 58899:58899 +0.00011266336187471834 56520:56520 +0.00011266336187471834 60725:60725 +0.00011266336187471834 56662:56662 +0.00011266336187471834 34503:34503 +0.00011266336187471834 35125:35125 +0.00011266336187471834 60010:60010 +0.00011266336187471834 58922:58922 +0.00011266336187471834 57918:57918 +0.00011266336187471834 58864:58864 +0.00011266336187471834 57176:57176 +0.00011266336187471834 35384:35384 +0.00011266336187471834 34926:34926 +0.00011266336187471834 59922:59922 +0.00011266336187471834 60537:60537 +0.00011266336187471834 33812:33812 +0.00011266336187471834 56588:56588 +0.00011266336187471834 56577:56577 +0.00011266336187471834 35550:35550 +0.00011266336187471834 57169:57169 +0.00011266336187471834 56807:56807 +0.00011266336187471834 34739:34739 +0.00011266336187471834 33010:33010 +0.00011266336187471834 60983:60983 +0.00011266336187471834 59928:59928 +0.00011266336187471834 33684:33684 +0.00011266336187471834 60568:60568 +0.00011266336187471834 58503:58503 +0.00011266336187471834 59048:59048 +0.00011266336187471834 57642:57642 +0.00011266336187471834 60322:60322 +0.00011266336187471834 58440:58440 +0.00011266336187471834 35191:35191 +0.00011266336187471834 33007:33007 +0.00011266336187471834 58490:58490 +0.00011266336187471834 35498:35498 +0.00011266336187471834 33245:33245 +0.00011266336187471834 35336:35336 +0.00011266336187471834 59875:59875 +0.00011266336187471834 56064:56064 +0.00011266336187471834 59334:59334 +0.00011266336187471834 32973:32973 +0.00011266336187471834 57520:57520 +0.00011266336187471834 33502:33502 +0.00011266336187471834 59070:59070 +0.00011266336187471834 35177:35177 +0.00011266336187471834 33014:33014 +0.00011266336187471834 56534:56534 +0.00011266336187471834 34524:34524 +0.00011266336187471834 33049:33049 +0.00011266336187471834 60460:60460 +0.00011266336187471834 59328:59328 +0.00011266336187471834 60754:60754 +0.00011266336187471834 35499:35499 +0.00011266336187471834 33116:33116 +0.00011266336187471834 59385:59385 +0.00011266336187471834 56211:56211 +0.00011266336187471834 33606:33606 +0.00011266336187471834 59515:59515 +0.00011266336187471834 34123:34123 +0.00011266336187471834 58688:58688 +0.00011266336187471834 58446:58446 +0.00011266336187471834 59296:59296 +0.00011266336187471834 60069:60069 +0.00011266336187471834 59097:59097 +0.00011266336187471834 59000:59000 +0.00011266336187471834 59437:59437 +0.00011266336187471834 33570:33570 +0.00011266336187471834 59221:59221 +0.00011266336187471834 59081:59081 +0.00011266336187471834 58886:58886 +0.00011266336187471834 34812:34812 +0.00011266336187471834 60648:60648 +0.00011266336187471834 56689:56689 +0.00011266336187471834 32954:32954 +0.00011266336187471834 57981:57981 +0.00011266336187471834 56843:56843 +0.00011266336187471834 35320:35320 +0.00011266336187471834 56637:56637 +0.00011266336187471834 55751:55751 +0.00011266336187471834 56019:56019 +0.00011266336187471834 35205:35205 +0.00011266336187471834 57997:57997 +0.00011266336187471834 59059:59059 +0.00011266336187471834 58341:58341 +0.00011266336187471834 35425:35425 +0.00011266336187471834 57077:57077 +0.00011266336187471834 56801:56801 +0.00011266336187471834 60902:60902 +0.00011266336187471834 57613:57613 +0.00011266336187471834 33757:33757 +0.00011266336187471834 60372:60372 +0.00011266336187471834 58982:58982 +0.00011266336187471834 55768:55768 +0.00011266336187471834 33632:33632 +0.00011266336187471834 59905:59905 +0.00011266336187471834 59121:59121 +0.00011266336187471834 55748:55748 +0.00011266336187471834 33704:33704 +0.00011266336187471834 34387:34387 +0.00011266336187471834 60676:60676 +0.00011266336187471834 35507:35507 +0.00011266336187471834 56368:56368 +0.00011266336187471834 56170:56170 +0.00011266336187471834 60468:60468 +0.00011266336187471834 60032:60032 +0.00011266336187471834 56177:56177 +0.00011266336187471834 56185:56185 +0.00011266336187471834 34449:34449 +0.00011266336187471834 56356:56356 +0.00011266336187471834 34764:34764 +0.00011266336187471834 58057:58057 +0.00011266336187471834 55860:55860 +0.00011266336187471834 60357:60357 +0.00011266336187471834 55633:55633 +0.00011266336187471834 55776:55776 +0.00011266336187471834 60847:60847 +0.00011266336187471834 34670:34670 +0.00011266336187471834 60199:60199 +0.00011266336187471834 56580:56580 +0.00011266336187471834 35075:35075 +0.00011266336187471834 55870:55870 +0.00011266336187471834 57739:57739 +0.00011266336187471834 60044:60044 +0.00011266336187471834 33296:33296 +0.00011266336187471834 59324:59324 +0.00011266336187471834 32888:32888 +0.00011266336187471834 33556:33556 +0.00011266336187471834 60942:60942 +0.00011266336187471834 59304:59304 +0.00011266336187471834 57179:57179 +0.00011266336187471834 33782:33782 +0.00011266336187471834 35325:35325 +0.00011266336187471834 33990:33990 +0.00011266336187471834 56030:56030 +0.00011266336187471834 33744:33744 +0.00011266336187471834 59630:59630 +0.00011266336187471834 34682:34682 +0.00011266336187471834 35121:35121 +0.00011266336187471834 33785:33785 +0.00011266336187471834 58339:58339 +0.00011266336187471834 33845:33845 +0.00011266336187471834 59114:59114 +0.00011266336187471834 57935:57935 +0.00011266336187471834 59724:59724 +0.00011266336187471834 59378:59378 +0.00011266336187471834 59289:59289 +0.00011266336187471834 58783:58783 +0.00011266336187471834 58825:58825 +0.00011266336187471834 58105:58105 +0.00011266336187471834 33890:33890 +0.00011266336187471834 57089:57089 +0.00011266336187471834 59025:59025 +0.00011266336187471834 56046:56046 +0.00011266336187471834 56861:56861 +0.00011266336187471834 58150:58150 +0.00011266336187471834 60699:60699 +0.00011266336187471834 58007:58007 +0.00011266336187471834 34623:34623 +0.00011266336187471834 33032:33032 +0.00011266336187471834 60164:60164 +0.00011266336187471834 33720:33720 +0.00011266336187471834 59051:59051 +0.00011266336187471834 60036:60036 +0.00011266336187471834 56385:56385 +0.00011266336187471834 59399:59399 +0.00011266336187471834 58156:58156 +0.00011266336187471834 57666:57666 +0.00011266336187471834 56683:56683 +0.00011266336187471834 60040:60040 +0.00011266336187471834 33385:33385 +0.00011266336187471834 59227:59227 +0.00011266336187471834 56148:56148 +0.00011266336187471834 34872:34872 +0.00011266336187471834 34193:34193 +0.00011266336187471834 59919:59919 +0.00011266336187471834 58022:58022 +0.00011266336187471834 59398:59398 +0.00011266336187471834 32848:32848 +0.00011266336187471834 60167:60167 +0.00011266336187471834 59532:59532 +0.00011266336187471834 33506:33506 +0.00011266336187471834 34686:34686 +0.00011266336187471834 59355:59355 +0.00011266336187471834 56156:56156 +0.00011266336187471834 60019:60019 +0.00011266336187471834 58093:58093 +0.00011266336187471834 57684:57684 +0.00011266336187471834 34035:34035 +0.00011266336187471834 60376:60376 +0.00011266336187471834 59681:59681 +0.00011266336187471834 34391:34391 +0.00011266336187471834 59140:59140 +0.00011266336187471834 55682:55682 +0.00011266336187471834 57022:57022 +0.00011266336187471834 56188:56188 +0.00011266336187471834 34165:34165 +0.00011266336187471834 56651:56651 +0.00011266336187471834 57172:57172 +0.00011266336187471834 32823:32823 +0.00011266336187471834 58117:58117 +0.00011266336187471834 58972:58972 +0.00011266336187471834 56631:56631 +0.00011266336187471834 55618:55618 +0.00011266336187471834 32816:32816 +0.00011266336187471834 34709:34709 +0.00011266336187471834 58633:58633 +0.00011266336187471834 34329:34329 +0.00011266336187471834 58354:58354 +0.00011266336187471834 55980:55980 +0.00011266336187471834 55904:55904 +0.00011266336187471834 34570:34570 +0.00011266336187471834 59824:59824 +0.00011266336187471834 59679:59679 +0.00011266336187471834 56029:56029 +0.00011266336187471834 58328:58328 +0.00011266336187471834 34930:34930 +0.00011266336187471834 34868:34868 +0.00011266336187471834 33843:33843 +0.00011266336187471834 59634:59634 +0.00011266336187471834 59360:59360 +0.00011266336187471834 35280:35280 +0.00011266336187471834 58620:58620 +0.00011266336187471834 34275:34275 +0.00011266336187471834 59440:59440 +0.00011266336187471834 58003:58003 +0.00011266336187471834 33050:33050 +0.00011266336187471834 34785:34785 +0.00011266336187471834 33205:33205 +0.00011266336187471834 56923:56923 +0.00011266336187471834 35178:35178 +0.00011266336187471834 34279:34279 +0.00011266336187471834 34258:34258 +0.00011266336187471834 33179:33179 +0.00011266336187471834 56544:56544 +0.00011266336187471834 59148:59148 +0.00011266336187471834 35503:35503 +0.00011266336187471834 60209:60209 +0.00011266336187471834 58074:58074 +0.00011266336187471834 57049:57049 +0.00011266336187471834 59645:59645 +0.00011266336187471834 60816:60816 +0.00011266336187471834 60018:60018 +0.00011266336187471834 57515:57515 +0.00011266336187471834 32903:32903 +0.00011266336187471834 60551:60551 +0.00011266336187471834 33442:33442 +0.00011266336187471834 33904:33904 +0.00011266336187471834 60824:60824 +0.00011266336187471834 60063:60063 +0.00011266336187471834 59820:59820 +0.00011266336187471834 33698:33698 +0.00011266336187471834 56596:56596 +0.00011266336187471834 60110:60110 +0.00011266336187471834 35426:35426 +0.00011266336187471834 56895:56895 +0.00011266336187471834 33960:33960 +0.00011266336187471834 33106:33106 +0.00011266336187471834 56882:56882 +0.00011266336187471834 59122:59122 +0.00011266336187471834 32960:32960 +0.00011266336187471834 56738:56738 +0.00011266336187471834 60704:60704 +0.00011266336187471834 60009:60009 +0.00011266336187471834 59053:59053 +0.00011266336187471834 32965:32965 +0.00011266336187471834 57966:57966 +0.00011266336187471834 55767:55767 +0.00011266336187471834 60833:60833 +0.00011266336187471834 60545:60545 +0.00011266336187471834 35341:35341 +0.00011266336187471834 58508:58508 +0.00011266336187471834 58342:58342 +0.00011266336187471834 33882:33882 +0.00011266336187471834 33711:33711 +0.00011266336187471834 56787:56787 +0.00011266336187471834 35019:35019 +0.00011266336187471834 33454:33454 +0.00011266336187471834 60280:60280 +0.00011266336187471834 56685:56685 +0.00011266336187471834 60029:60029 +0.00011266336187471834 60716:60716 +0.00011266336187471834 33192:33192 +0.00011266336187471834 33498:33498 +0.00011266336187471834 58029:58029 +0.00011266336187471834 59941:59941 +0.00011266336187471834 35142:35142 +0.00011266336187471834 33036:33036 +0.00011266336187471834 60924:60924 +0.00011266336187471834 58782:58782 +0.00011266336187471834 56392:56392 +0.00011266336187471834 59589:59589 +0.00011266336187471834 57633:57633 +0.00011266336187471834 57101:57101 +0.00011266336187471834 34253:34253 +0.00011266336187471834 34556:34556 +0.00011266336187471834 60082:60082 +0.00011266336187471834 33717:33717 +0.00011266336187471834 58894:58894 +0.00011266336187471834 55658:55658 +0.00011266336187471834 55931:55931 +0.00011266336187471834 60450:60450 +0.00011266336187471834 56736:56736 +0.00011266336187471834 55714:55714 +0.00011266336187471834 34699:34699 +0.00011266336187471834 60960:60960 +0.00011266336187471834 33679:33679 +0.00011266336187471834 60689:60689 +0.00011266336187471834 35087:35087 +0.00011266336187471834 60302:60302 +0.00011266336187471834 59490:59490 +0.00011266336187471834 56150:56150 +0.00011266336187471834 59971:59971 +0.00011266336187471834 34124:34124 +0.00011266336187471834 58857:58857 +0.00011266336187471834 57443:57443 +0.00011266336187471834 32943:32943 +0.00011266336187471834 60272:60272 +0.00011266336187471834 60972:60972 +0.00011266336187471834 58765:58765 +0.00011266336187471834 32849:32849 +0.00011266336187471834 32854:32854 +0.00011266336187471834 33712:33712 +0.00011266336187471834 56614:56614 +0.00011266336187471834 56223:56223 +0.00011266336187471834 35487:35487 +0.00011266336187471834 59223:59223 +0.00011266336187471834 56389:56389 +0.00011266336187471834 35510:35510 +0.00011266336187471834 34870:34870 +0.00011266336187471834 56372:56372 +0.00011266336187471834 34519:34519 +0.00011266336187471834 33267:33267 +0.00011266336187471834 57616:57616 +0.00011266336187471834 56820:56820 +0.00011266336187471834 59625:59625 +0.00011266336187471834 58537:58537 +0.00011266336187471834 59259:59259 +0.00011266336187471834 33531:33531 +0.00011266336187471834 59553:59553 +0.00011266336187471834 60601:60601 +0.00011266336187471834 56261:56261 +0.00011266336187471834 57420:57420 +0.00011266336187471834 58907:58907 +0.00011266336187471834 57996:57996 +0.00011266336187471834 56640:56640 +0.00011266336187471834 57921:57921 +0.00011266336187471834 56623:56623 +0.00011266336187471834 60403:60403 +0.00011266336187471834 58832:58832 +0.00011266336187471834 58818:58818 +0.00011266336187471834 60827:60827 +0.00011266336187471834 57411:57411 +0.00011266336187471834 35512:35512 +0.00011266336187471834 60454:60454 +0.00011266336187471834 34666:34666 +0.00011266336187471834 33505:33505 +0.00011266336187471834 57827:57827 +0.00011266336187471834 57451:57451 +0.00011266336187471834 32891:32891 +0.00011266336187471834 34936:34936 +0.00011266336187471834 60742:60742 +0.00011266336187471834 58213:58213 +0.00011266336187471834 56092:56092 +0.00011266336187471834 60896:60896 +0.00011266336187471834 58177:58177 +0.00011266336187471834 34831:34831 +0.00011266336187471834 59157:59157 +0.00011266336187471834 57250:57250 +0.00011266336187471834 56812:56812 +0.00011266336187471834 55869:55869 +0.00011266336187471834 35383:35383 +0.00011266336187471834 58852:58852 +0.00011266336187471834 59654:59654 +0.00011266336187471834 57563:57563 +0.00011266336187471834 33220:33220 +0.00011266336187471834 59258:59258 +0.00011266336187471834 57749:57749 +0.00011266336187471834 57309:57309 +0.00011266336187471834 57057:57057 +0.00011266336187471834 34849:34849 +0.00011266336187471834 56416:56416 +0.00011266336187471834 35251:35251 +0.00011266336187471834 33611:33611 +0.00011266336187471834 58565:58565 +0.00011266336187471834 55890:55890 +0.00011266336187471834 35446:35446 +0.00011266336187471834 33093:33093 +0.00011266336187471834 56282:56282 +0.00011266336187471834 35120:35120 +0.00011266336187471834 33590:33590 +0.00011266336187471834 33214:33214 +0.00011266336187471834 33108:33108 +0.00011266336187471834 32985:32985 +0.00011266336187471834 60652:60652 +0.00011266336187471834 34691:34691 +0.00011266336187471834 34448:34448 +0.00011266336187471834 34421:34421 +0.00011266336187471834 58399:58399 +0.00011266336187471834 34172:34172 +0.00011266336187471834 60682:60682 +0.00011266336187471834 34885:34885 +0.00011266336187471834 57159:57159 +0.00011266336187471834 35052:35052 +0.00011266336187471834 34267:34267 +0.00011266336187471834 33813:33813 +0.00011266336187471834 34515:34515 +0.00011266336187471834 60035:60035 +0.00011266336187471834 58663:58663 +0.00011266336187471834 34131:34131 +0.00011266336187471834 55910:55910 +0.00011266336187471834 60989:60989 +0.00011266336187471834 32982:32982 +0.00011266336187471834 59286:59286 +0.00011266336187471834 35160:35160 +0.00011266336187471834 33626:33626 +0.00011266336187471834 59929:59929 +0.00011266336187471834 59611:59611 +0.00011266336187471834 60227:60227 +0.00011266336187471834 34036:34036 +0.00011266336187471834 33544:33544 +0.00011266336187471834 33977:33977 +0.00011266336187471834 57582:57582 +0.00011266336187471834 55826:55826 +0.00011266336187471834 58845:58845 +0.00011266336187471834 33472:33472 +0.00011266336187471834 34082:34082 +0.00011266336187471834 57360:57360 +0.00011266336187471834 35508:35508 +0.00011266336187471834 60587:60587 +0.00011266336187471834 59575:59575 +0.00011266336187471834 33685:33685 +0.00011266336187471834 60472:60472 +0.00011266336187471834 60201:60201 +0.00011266336187471834 59997:59997 +0.00011266336187471834 59368:59368 +0.00011266336187471834 56004:56004 +0.00011266336187471834 59807:59807 +0.00011266336187471834 55645:55645 +0.00011266336187471834 56431:56431 +0.00011266336187471834 58898:58898 +0.00011266336187471834 57943:57943 +0.00011266336187471834 33791:33791 +0.00011266336187471834 57184:57184 +0.00011266336187471834 56804:56804 +0.00011266336187471834 33004:33004 +0.00011266336187471834 35452:35452 +0.00011266336187471834 60301:60301 +0.00011266336187471834 35009:35009 +0.00011266336187471834 60873:60873 +0.00011266336187471834 34183:34183 +0.00011266336187471834 33953:33953 +0.00011266336187471834 58916:58916 +0.00011266336187471834 60709:60709 +0.00011266336187471834 60003:60003 +0.00011266336187471834 57627:57627 +0.00011266336187471834 33167:33167 +0.00011266336187471834 33324:33324 +0.00011266336187471834 56460:56460 +0.00011266336187471834 59288:59288 +0.00011266336187471834 55802:55802 +0.00011266336187471834 34184:34184 +0.00011266336187471834 56298:56298 +0.00011266336187471834 33094:33094 +0.00011266336187471834 57389:57389 +0.00011266336187471834 34255:34255 +0.00011266336187471834 58368:58368 +0.00011266336187471834 57800:57800 +0.00011266336187471834 58335:58335 +0.00011266336187471834 59881:59881 +0.00011266336187471834 59423:59423 +0.00011266336187471834 59242:59242 +0.00011266336187471834 60548:60548 +0.00011266336187471834 57385:57385 +0.00011266336187471834 60169:60169 +0.00011266336187471834 60970:60970 +0.00011266336187471834 59595:59595 +0.00011266336187471834 56215:56215 +0.00011266336187471834 34546:34546 +0.00011266336187471834 33876:33876 +0.00011266336187471834 55902:55902 +0.00011266336187471834 33182:33182 +0.00011266336187471834 59341:59341 +0.00011266336187471834 58310:58310 +0.00011266336187471834 58545:58545 +0.00011266336187471834 34676:34676 +0.00011266336187471834 33605:33605 +0.00011266336187471834 849:849 +0.00011266336187471834 55664:55664 +0.00011266336187471834 60499:60499 +0.00011266336187471834 33923:33923 +0.00011266336187471834 56657:56657 +0.00011266336187471834 32910:32910 +0.00011266336187471834 59584:59584 +0.00011266336187471834 33577:33577 +0.00011266336187471834 60868:60868 +0.00011266336187471834 59199:59199 +0.00011266336187471834 33955:33955 +0.00011266336187471834 57037:57037 +0.00011266336187471834 60966:60966 +0.00011266336187471834 59478:59478 +0.00011266336187471834 56119:56119 +0.00011266336187471834 35007:35007 +0.00011266336187471834 57701:57701 +0.00011266336187471834 57062:57062 +0.00011266336187471834 60398:60398 +0.00011266336187471834 56813:56813 +0.00011266336187471834 35458:35458 +0.00011266336187471834 35433:35433 +0.00011266336187471834 55636:55636 +0.00011266336187471834 33630:33630 +0.00011266336187471834 59464:59464 +0.00011266336187471834 33290:33290 +0.00011266336187471834 59458:59458 +0.00011266336187471834 59075:59075 +0.00011266336187471834 60732:60732 +0.00011266336187471834 60281:60281 +0.00011266336187471834 55933:55933 +0.00011266336187471834 35342:35342 +0.00011266336187471834 57391:57391 +0.00011266336187471834 34441:34441 +0.00011266336187471834 60334:60334 +0.00011266336187471834 56197:56197 +0.00011266336187471834 32904:32904 +0.00011266336187471834 59078:59078 +0.00011266336187471834 60366:60366 +0.00011266336187471834 56835:56835 +0.00011266336187471834 34001:34001 +0.00011266336187471834 33076:33076 +0.00011266336187471834 59892:59892 +0.00011266336187471834 34135:34135 +0.00011266336187471834 60770:60770 +0.00011266336187471834 35095:35095 +0.00011266336187471834 34969:34969 +0.00011266336187471834 55724:55724 +0.00011266336187471834 34145:34145 +0.00011266336187471834 33943:33943 +0.00011266336187471834 55912:55912 +0.00011266336187471834 35187:35187 +0.00011266336187471834 33337:33337 +0.00011266336187471834 34997:34997 +0.00011266336187471834 57626:57626 +0.00011266336187471834 57168:57168 +0.00011266336187471834 58834:58834 +0.00011266336187471834 55942:55942 +0.00011266336187471834 57365:57365 +0.00011266336187471834 60914:60914 +0.00011266336187471834 34593:34593 +0.00011266336187471834 58800:58800 +0.00011266336187471834 57522:57522 +0.00011266336187471834 57011:57011 +0.00011266336187471834 59566:59566 +0.00011266336187471834 35173:35173 +0.00011266336187471834 34681:34681 +0.00011266336187471834 56590:56590 +0.00011266336187471834 33857:33857 +0.00011266336187471834 59708:59708 +0.00011266336187471834 33755:33755 +0.00011266336187471834 32827:32827 +0.00011266336187471834 59414:59414 +0.00011266336187471834 57336:57336 +0.00011266336187471834 33458:33458 +0.00011266336187471834 60720:60720 +0.00011266336187471834 34285:34285 +0.00011266336187471834 33999:33999 +0.00011266336187471834 32956:32956 +0.00011266336187471834 58251:58251 +0.00011266336187471834 56890:56890 +0.00011266336187471834 58431:58431 +0.00011266336187471834 33298:33298 +0.00011266336187471834 56805:56805 +0.00011266336187471834 55888:55888 +0.00011266336187471834 57629:57629 +0.00011266336187471834 33110:33110 +0.00011266336187471834 56846:56846 +0.00011266336187471834 60387:60387 +0.00011266336187471834 59149:59149 +0.00011266336187471834 56792:56792 +0.00011266336187471834 55688:55688 +0.00011266336187471834 33445:33445 +0.00011266336187471834 33180:33180 +0.00011266336187471834 59158:59158 +0.00011266336187471834 58961:58961 +0.00011266336187471834 56094:56094 +0.00011266336187471834 59939:59939 +0.00011266336187471834 57024:57024 +0.00011266336187471834 56739:56739 +0.00011266336187471834 59970:59970 +0.00011266336187471834 55729:55729 +0.00011266336187471834 56865:56865 +0.00011266336187471834 60022:60022 +0.00011266336187471834 57861:57861 +0.00011266336187471834 56067:56067 +0.00011266336187471834 34548:34548 +0.00011266336187471834 33729:33729 +0.00011266336187471834 57452:57452 +0.00011266336187471834 56896:56896 +0.00011266336187471834 58946:58946 +0.00011266336187471834 56700:56700 +0.00011266336187471834 57278:57278 +0.00011266336187471834 60838:60838 +0.00011266336187471834 60715:60715 +0.00011266336187471834 35289:35289 +0.00011266336187471834 35515:35515 +0.00011266336187471834 33998:33998 +0.00011266336187471834 34989:34989 +0.00011266336187471834 59383:59383 +0.00011266336187471834 59306:59306 +0.00011266336187471834 57346:57346 +0.00011266336187471834 55702:55702 +0.00011266336187471834 34811:34811 +0.00011266336187471834 56371:56371 +0.00011266336187471834 34446:34446 +0.00011266336187471834 33601:33601 +0.00011266336187471834 57321:57321 +0.00011266336187471834 60000:60000 +0.00011266336187471834 56003:56003 +0.00011266336187471834 57012:57012 +0.00011266336187471834 34037:34037 +0.00011266336187471834 57223:57223 +0.00011266336187471834 34603:34603 +0.00011266336187471834 58658:58658 +0.00011266336187471834 35137:35137 +0.00011266336187471834 59036:59036 +0.00011266336187471834 57615:57615 +0.00011266336187471834 57065:57065 +0.00011266336187471834 59766:59766 +0.00011266336187471834 34303:34303 +0.00011266336187471834 57838:57838 +0.00011266336187471834 35084:35084 +0.00011266336187471834 56229:56229 +0.00011266336187471834 60607:60607 +0.00011266336187471834 59041:59041 +0.00011266336187471834 58881:58881 +0.00011266336187471834 59856:59856 +0.00011266336187471834 59238:59238 +0.00011266336187471834 34506:34506 +0.00011266336187471834 34120:34120 +0.00011266336187471834 55728:55728 +0.00011266336187471834 35017:35017 +0.00011266336187471834 56774:56774 +0.00011266336187471834 60957:60957 +0.00011266336187471834 59896:59896 +0.00011266336187471834 58711:58711 +0.00011266336187471834 60668:60668 +0.00011266336187471834 56169:56169 +0.00011266336187471834 32831:32831 +0.00011266336187471834 60963:60963 +0.00011266336187471834 60360:60360 +0.00011266336187471834 57241:57241 +0.00011266336187471834 59957:59957 +0.00011266336187471834 33552:33552 +0.00011266336187471834 55734:55734 +0.00011266336187471834 33384:33384 +0.00011266336187471834 57070:57070 +0.00011266336187471834 57418:57418 +0.00011266336187471834 57149:57149 +0.00011266336187471834 59735:59735 +0.00011266336187471834 60202:60202 +0.00011266336187471834 34712:34712 +0.00011266336187471834 55685:55685 +0.00011266336187471834 60629:60629 +0.00011266336187471834 57048:57048 +0.00011266336187471834 33089:33089 +0.00011266336187471834 59068:59068 +0.00011266336187471834 59001:59001 +0.00011266336187471834 35193:35193 +0.00011266336187471834 34375:34375 +0.00011266336187471834 56793:56793 +0.00011266336187471834 34108:34108 +0.00011266336187471834 60331:60331 +0.00011266336187471834 59885:59885 +0.00011266336187471834 33037:33037 +0.00011266336187471834 57377:57377 +0.00011266336187471834 56244:56244 +0.00011266336187471834 34211:34211 +0.00011266336187471834 57687:57687 +0.00011266336187471834 59064:59064 +0.00011266336187471834 60655:60655 +0.00011266336187471834 56619:56619 +0.00011266336187471834 57598:57598 +0.00011266336187471834 33620:33620 +0.00011266336187471834 56107:56107 +0.00011266336187471834 59546:59546 +0.00011266336187471834 33459:33459 +0.00011266336187471834 34085:34085 +0.00011266336187471834 60020:60020 +0.00011266336187471834 34304:34304 +0.00011266336187471834 59023:59023 +0.00011266336187471834 57708:57708 +0.00011266336187471834 34883:34883 +0.00011266336187471834 60628:60628 +0.00011266336187471834 59659:59659 +0.00011266336187471834 35086:35086 +0.00011266336187471834 60913:60913 +0.00011266336187471834 58230:58230 +0.00011266336187471834 55615:55615 +0.00011266336187471834 33349:33349 +0.00011266336187471834 56339:56339 +0.00011266336187471834 33835:33835 +0.00011266336187471834 32843:32843 +0.00011266336187471834 34283:34283 +0.00011266336187471834 34062:34062 +0.00011266336187471834 60394:60394 +0.00011266336187471834 58978:58978 +0.00011266336187471834 58732:58732 +0.00011266336187471834 35228:35228 +0.00011266336187471834 60222:60222 +0.00011266336187471834 58826:58826 +0.00011266336187471834 56675:56675 +0.00011266336187471834 33321:33321 +0.00011266336187471834 33306:33306 +0.00011266336187471834 59382:59382 +0.00011266336187471834 59793:59793 +0.00011266336187471834 57828:57828 +0.00011266336187471834 56214:56214 +0.00011266336187471834 34000:34000 +0.00011266336187471834 59741:59741 +0.00011266336187471834 59233:59233 +0.00011266336187471834 57188:57188 +0.00011266336187471834 59747:59747 +0.00011266336187471834 57923:57923 +0.00011266336187471834 57967:57967 +0.00011266336187471834 60938:60938 +0.00011266336187471834 57856:57856 +0.00011266336187471834 34156:34156 +0.00011266336187471834 58418:58418 +0.00011266336187471834 55638:55638 +0.00011266336187471834 33373:33373 +0.00011266336187471834 59435:59435 +0.00011266336187471834 58462:58462 +0.00011266336187471834 59580:59580 +0.00011266336187471834 60535:60535 +0.00011266336187471834 58442:58442 +0.00011266336187471834 57850:57850 +0.00011266336187471834 58224:58224 +0.00011266336187471834 57480:57480 +0.00011266336187471834 58011:58011 +0.00011266336187471834 59700:59700 +0.00011266336187471834 56581:56581 +0.00011266336187471834 60386:60386 +0.00011266336187471834 59485:59485 +0.00011266336187471834 60844:60844 +0.00011266336187471834 60407:60407 +0.00011266336187471834 56715:56715 +0.00011266336187471834 57301:57301 +0.00011266336187471834 34761:34761 +0.00011266336187471834 33913:33913 +0.00011266336187471834 56485:56485 +0.00011266336187471834 60184:60184 +0.00011266336187471834 60946:60946 +0.00011266336187471834 59101:59101 +0.00011266336187471834 57289:57289 +0.00011266336187471834 60317:60317 +0.00011266336187471834 59727:59727 +0.00011266336187471834 32883:32883 +0.00011266336187471834 57803:57803 +0.00011266336187471834 60940:60940 +0.00011266336187471834 59866:59866 +0.00011266336187471834 33721:33721 +0.00011266336187471834 60792:60792 +0.00011266336187471834 59239:59239 +0.00011266336187471834 57675:57675 +0.00011266336187471834 57806:57806 +0.00011266336187471834 56451:56451 +0.00011266336187471834 34055:34055 +0.00011266336187471834 56902:56902 +0.00011266336187471834 60061:60061 +0.00011266336187471834 34751:34751 +0.00011266336187471834 34641:34641 +0.00011266336187471834 58649:58649 +0.00011266336187471834 34757:34757 +0.00011266336187471834 58483:58483 +0.00011266336187471834 33168:33168 +0.00011266336187471834 60662:60662 +0.00011266336187471834 56222:56222 +0.00011266336187471834 35141:35141 +0.00011266336187471834 59166:59166 +0.00011266336187471834 59236:59236 +0.00011266336187471834 60508:60508 +0.00011266336187471834 58585:58585 +0.00011266336187471834 56916:56916 +0.00011266336187471834 59377:59377 +0.00011266336187471834 60908:60908 +0.00011266336187471834 33395:33395 +0.00011266336187471834 58108:58108 +0.00011266336187471834 56718:56718 +0.00011266336187471834 58118:58118 +0.00011266336187471834 59889:59889 +0.00011266336187471834 60726:60726 +0.00011266336187471834 33991:33991 +0.00011266336187471834 58768:58768 +0.00011266336187471834 56884:56884 +0.00011266336187471834 56881:56881 +0.00011266336187471834 35330:35330 +0.00011266336187471834 32890:32890 +0.00011266336187471834 55637:55637 +0.00011266336187471834 33663:33663 +0.00011266336187471834 58441:58441 +0.00011266336187471834 57889:57889 +0.00011266336187471834 33474:33474 +0.00011266336187471834 34940:34940 +0.00011266336187471834 34226:34226 +0.00011266336187471834 60952:60952 +0.00011266336187471834 33354:33354 +0.00011266336187471834 60894:60894 +0.00011266336187471834 57216:57216 +0.00011266336187471834 34525:34525 +0.00011266336187471834 57536:57536 +0.00011266336187471834 32879:32879 +0.00011266336187471834 57095:57095 +0.00011266336187471834 34137:34137 +0.00011266336187471834 34048:34048 +0.00011266336187471834 55924:55924 +0.00011266336187471834 33525:33525 +0.00011266336187471834 34260:34260 +0.00011266336187471834 55701:55701 +0.00011266336187471834 34040:34040 +0.00011266336187471834 59815:59815 +0.00011266336187471834 58950:58950 +0.00011266336187471834 34647:34647 +0.00011266336187471834 34599:34599 +0.00011266336187471834 32932:32932 +0.00011266336187471834 60563:60563 +0.00011266336187471834 56330:56330 +0.00011266336187471834 55944:55944 +0.00011266336187471834 58469:58469 +0.00011266336187471834 35016:35016 +0.00011266336187471834 34960:34960 +0.00011266336187471834 60354:60354 +0.00011266336187471834 56264:56264 +0.00011266336187471834 34051:34051 +0.00011266336187471834 60189:60189 +0.00011266336187471834 57423:57423 +0.00011266336187471834 34861:34861 +0.00011266336187471834 56072:56072 +0.00011266336187471834 35484:35484 +0.00011266336187471834 60620:60620 +0.00011266336187471834 57107:57107 +0.00011266336187471834 32800:32800 +0.00011266336187471834 60447:60447 +0.00011266336187471834 56799:56799 +0.00011266336187471834 59456:59456 +0.00011266336187471834 59293:59293 +0.00011266336187471834 59292:59292 +0.00011266336187471834 35485:35485 +0.00011266336187471834 58103:58103 +0.00011266336187471834 59594:59594 +0.00011266336187471834 57013:57013 +0.00011266336187471834 57178:57178 +0.00011266336187471834 33825:33825 +0.00011266336187471834 59959:59959 +0.00011266336187471834 56199:56199 +0.00011266336187471834 58963:58963 +0.00011266336187471834 35472:35472 +0.00011266336187471834 60168:60168 +0.00011266336187471834 59574:59574 +0.00011266336187471834 57738:57738 +0.00011266336187471834 33629:33629 +0.00011266336187471834 58923:58923 +0.00011266336187471834 59778:59778 +0.00011266336187471834 35097:35097 +0.00011266336187471834 33428:33428 +0.00011266336187471834 60744:60744 +0.00011266336187471834 33793:33793 +0.00011266336187471834 60675:60675 +0.00011266336187471834 34257:34257 +0.00011266336187471834 58456:58456 +0.00011266336187471834 34460:34460 +0.00011266336187471834 33609:33609 +0.00011266336187471834 60231:60231 +0.00011266336187471834 59300:59300 +0.00011266336187471834 59629:59629 +0.00011266336187471834 58367:58367 +0.00011266336187471834 35333:35333 +0.00011266336187471834 33618:33618 +0.00011266336187471834 60613:60613 +0.00011266336187471834 57211:57211 +0.00011266336187471834 60825:60825 +0.00011266336187471834 34875:34875 +0.00011266336187471834 35064:35064 +0.00011266336187471834 35307:35307 +0.00011266336187471834 59200:59200 +0.00011266336187471834 58464:58464 +0.00011266336187471834 57948:57948 +0.00011266336187471834 56174:56174 +0.00011266336187471834 56794:56794 +0.00011266336187471834 55973:55973 +0.00011266336187471834 33436:33436 +0.00011266336187471834 59832:59832 +0.00011266336187471834 35225:35225 +0.00011266336187471834 34961:34961 +0.00011266336187471834 59518:59518 +0.00011266336187471834 55815:55815 +0.00011266336187471834 59252:59252 +0.00011266336187471834 55678:55678 +0.00011266336187471834 34457:34457 +0.00011266336187471834 59154:59154 +0.00011266336187471834 57884:57884 +0.00011266336187471834 56573:56573 +0.00011266336187471834 60603:60603 +0.00011266336187471834 60288:60288 +0.00011266336187471834 33722:33722 +0.00011266336187471834 33331:33331 +0.00011266336187471834 55623:55623 +0.00011266336187471834 35521:35521 +0.00011266336187471834 56968:56968 +0.00011266336187471834 33789:33789 +0.00011266336187471834 56088:56088 +0.00011266336187471834 57280:57280 +0.00011266336187471834 33628:33628 +0.00011266336187471834 33963:33963 +0.00011266336187471834 58715:58715 +0.00011266336187471834 55873:55873 +0.00011266336187471834 34271:34271 +0.00011266336187471834 34539:34539 +0.00011266336187471834 33247:33247 +0.00011266336187471834 56709:56709 +0.00011266336187471834 56680:56680 +0.00011266336187471834 60664:60664 +0.00011266336187471834 55619:55619 +0.00011266336187471834 56687:56687 +0.00011266336187471834 60711:60711 +0.00011266336187471834 60517:60517 +0.00011266336187471834 33065:33065 +0.00011266336187471834 33488:33488 +0.00011266336187471834 56858:56858 +0.00011266336187471834 33496:33496 +0.00011266336187471834 58278:58278 +0.00011266336187471834 33041:33041 +0.00011266336187471834 58933:58933 +0.00011266336187471834 58216:58216 +0.00011266336187471834 56393:56393 +0.00011266336187471834 58181:58181 +0.00011266336187471834 55909:55909 +0.00011266336187471834 32814:32814 +0.00011266336187471834 60388:60388 +0.00011266336187471834 33211:33211 +0.00011266336187471834 60582:60582 +0.00011266336187471834 57855:57855 +0.00011266336187471834 56937:56937 +0.00011266336187471834 34407:34407 +0.00011266336187471834 59284:59284 +0.00011266336187471834 60490:60490 +0.00011266336187471834 58632:58632 +0.00011266336187471834 58047:58047 +0.00011266336187471834 57374:57374 +0.00011266336187471834 56027:56027 +0.00011266336187471834 56907:56907 +0.00011266336187471834 59234:59234 +0.00011266336187471834 58685:58685 +0.00011266336187471834 57368:57368 +0.00011266336187471834 58990:58990 +0.00011266336187471834 56422:56422 +0.00011266336187471834 58174:58174 +0.00011266336187471834 33693:33693 +0.00011266336187471834 58119:58119 +0.00011266336187471834 34754:34754 +0.00011266336187471834 56346:56346 +0.00011266336187471834 56146:56146 +0.00011266336187471834 55681:55681 +0.00011266336187471834 33909:33909 +0.00011266336187471834 55791:55791 +0.00011266336187471834 35422:35422 +0.00011266336187471834 57599:57599 +0.00011266336187471834 55794:55794 +0.00011266336187471834 59796:59796 +0.00011266336187471834 56173:56173 +0.00011266336187471834 60406:60406 +0.00011266336187471834 59646:59646 +0.00011266336187471834 33410:33410 +0.00011266336187471834 57649:57649 +0.00011266336187471834 60918:60918 +0.00011266336187471834 60870:60870 +0.00011266336187471834 55613:55613 +0.00011266336187471834 57181:57181 +0.00011266336187471834 35489:35489 +0.00011266336187471834 35124:35124 +0.00011266336187471834 34755:34755 +0.00011266336187471834 35242:35242 +0.00011266336187471834 34079:34079 +0.00011266336187471834 58866:58866 +0.00011266336187471834 55642:55642 +0.00011266336187471834 60338:60338 +0.00011266336187471834 57396:57396 +0.00011266336187471834 33932:33932 +0.00011266336187471834 59853:59853 +0.00011266336187471834 60935:60935 +0.00011266336187471834 34417:34417 +0.00011266336187471834 58246:58246 +0.00011266336187471834 55635:55635 +0.00011266336187471834 35322:35322 +0.00011266336187471834 33281:33281 +0.00011266336187471834 57600:57600 +0.00011266336187471834 34083:34083 +0.00011266336187471834 32918:32918 +0.00011266336187471834 58390:58390 +0.00011266336187471834 60470:60470 +0.00011266336187471834 60318:60318 +0.00011266336187471834 32980:32980 +0.00011266336187471834 57293:57293 +0.00011266336187471834 58393:58393 +0.00011266336187471834 60810:60810 +0.00011266336187471834 56109:56109 +0.00011266336187471834 55855:55855 +0.00011266336187471834 59990:59990 +0.00011266336187471834 34068:34068 +0.00011266336187471834 60415:60415 +0.00011266336187471834 57564:57564 +0.00011266336187471834 33944:33944 +0.00011266336187471834 56609:56609 +0.00011266336187471834 34238:34238 +0.00011266336187471834 57460:57460 +0.00011266336187471834 35481:35481 +0.00011266336187471834 35202:35202 +0.00011266336187471834 34262:34262 +0.00011266336187471834 59069:59069 +0.00011266336187471834 34103:34103 +0.00011266336187471834 59192:59192 +0.00011266336187471834 33369:33369 +0.00011266336187471834 34091:34091 +0.00011266336187471834 60131:60131 +0.00011266336187471834 60961:60961 +0.00011266336187471834 59491:59491 +0.00011266336187471834 57492:57492 +0.00011266336187471834 56665:56665 +0.00011266336187471834 57137:57137 +0.00011266336187471834 55823:55823 +0.00011266336187471834 58193:58193 +0.00011266336187471834 34909:34909 +0.00011266336187471834 60622:60622 +0.00011266336187471834 34274:34274 +0.00011266336187471834 32946:32946 +0.00011266336187471834 58517:58517 +0.00011266336187471834 56078:56078 +0.00011266336187471834 35241:35241 +0.00011266336187471834 59858:59858 +0.00011266336187471834 33588:33588 +0.00011266336187471834 33176:33176 +0.00011266336187471834 59872:59872 +0.00011266336187471834 56767:56767 +0.00011266336187471834 60180:60180 +0.00011266336187471834 58113:58113 +0.00011266336187471834 34434:34434 +0.00011266336187471834 56084:56084 +0.00011266336187471834 57373:57373 +0.00011266336187471834 59336:59336 +0.00011266336187471834 34154:34154 +0.00011266336187471834 59655:59655 +0.00011266336187471834 57723:57723 +0.00011266336187471834 34422:34422 +0.00011266336187471834 57774:57774 +0.00011266336187471834 34844:34844 +0.00011266336187471834 58061:58061 +0.00011266336187471834 58025:58025 +0.00011266336187471834 32863:32863 +0.00011266336187471834 56997:56997 +0.00011266336187471834 56963:56963 +0.00011266336187471834 58705:58705 +0.00011266336187471834 59674:59674 +0.00011266336187471834 58931:58931 +0.00011266336187471834 57092:57092 +0.00011266336187471834 33291:33291 +0.00011266336187471834 59730:59730 +0.00011266336187471834 57673:57673 +0.00011266336187471834 57659:57659 +0.00011266336187471834 34694:34694 +0.00011266336187471834 33568:33568 +0.00011266336187471834 60874:60874 +0.00011266336187471834 33838:33838 +0.00011266336187471834 59319:59319 +0.00011266336187471834 58709:58709 +0.00011266336187471834 55974:55974 +0.00011266336187471834 34288:34288 +0.00011266336187471834 33964:33964 +0.00011266336187471834 59749:59749 +0.00011266336187471834 55692:55692 +0.00011266336187471834 34980:34980 +0.00011266336187471834 58473:58473 +0.00011266336187471834 57922:57922 +0.00011266336187471834 57180:57180 +0.00011266336187471834 34884:34884 +0.00011266336187471834 59784:59784 +0.00011266336187471834 33886:33886 +0.00011266336187471834 33914:33914 +0.00011266336187471834 58920:58920 +0.00011266336187471834 35298:35298 +0.00011266336187471834 60325:60325 +0.00011266336187471834 59582:59582 +0.00011266336187471834 58521:58521 +0.00011266336187471834 58408:58408 +0.00011266336187471834 33429:33429 +0.00011266336187471834 58124:58124 +0.00011266336187471834 55987:55987 +0.00011266336187471834 60974:60974 +0.00011266336187471834 60039:60039 +0.00011266336187471834 57402:57402 +0.00011266336187471834 57284:57284 +0.00011266336187471834 34302:34302 +0.00011266336187471834 33768:33768 +0.00011266336187471834 58816:58816 +0.00011266336187471834 34534:34534 +0.00011266336187471834 56750:56750 +0.00011266336187471834 32824:32824 +0.00011266336187471834 55998:55998 +0.00011266336187471834 55951:55951 +0.00011266336187471834 60313:60313 +0.00011266336187471834 58704:58704 +0.00011266336187471834 57957:57957 +0.00011266336187471834 34806:34806 +0.00011266336187471834 33690:33690 +0.00011266336187471834 55699:55699 +0.00011266336187471834 34582:34582 +0.00011266336187471834 60596:60596 +0.00011266336187471834 55693:55693 +0.00011266336187471834 59504:59504 +0.00011266336187471834 34562:34562 +0.00011266336187471834 60785:60785 +0.00011266336187471834 59380:59380 +0.00011266336187471834 34169:34169 +0.00011266336187471834 55652:55652 +0.00011266336187471834 58589:58589 +0.00011266336187471834 34431:34431 +0.00011266336187471834 59146:59146 +0.00011266336187471834 33716:33716 +0.00011266336187471834 57862:57862 +0.00011266336187471834 57612:57612 +0.00011266336187471834 34820:34820 +0.00011266336187471834 33695:33695 +0.00011266336187471834 60496:60496 +0.00011266336187471834 60428:60428 +0.00011266336187471834 57994:57994 +0.00011266336187471834 33164:33164 +0.00011266336187471834 58050:58050 +0.00011266336187471834 59494:59494 +0.00011266336187471834 32867:32867 +0.00011266336187471834 33849:33849 +0.00011266336187471834 33352:33352 +0.00011266336187471834 57980:57980 +0.00011266336187471834 33193:33193 +0.00011266336187471834 57669:57669 +0.00011266336187471834 34286:34286 +0.00011266336187471834 34750:34750 +0.00011266336187471834 58466:58466 +0.00011266336187471834 56181:56181 +0.00011266336187471834 56182:56182 +0.00011266336187471834 34390:34390 +0.00011266336187471834 56585:56585 +0.00011266336187471834 55719:55719 +0.00011266336187471834 55821:55821 +0.00011266336187471834 59528:59528 +0.00011266336187471834 34899:34899 +0.00011266336187471834 56052:56052 +0.00011266336187471834 34413:34413 +0.00011266336187471834 34097:34097 +0.00011266336187471834 59243:59243 +0.00011266336187471834 34414:34414 +0.00011266336187471834 56800:56800 +0.00011266336187471834 34727:34727 +0.00011266336187471834 34369:34369 +0.00011266336187471834 59438:59438 +0.00011266336187471834 58382:58382 +0.00011266336187471834 34140:34140 +0.00011266336187471834 55986:55986 +0.00011266336187471834 57593:57593 +0.00011266336187471834 55668:55668 +0.00011266336187471834 58533:58533 +0.00011266336187471834 35189:35189 +0.00011266336187471834 35175:35175 +0.00011266336187471834 33660:33660 +0.00011266336187471834 57852:57852 +0.00011266336187471834 55813:55813 +0.00011266336187471834 34409:34409 +0.00011266336187471834 35229:35229 +0.00011266336187471834 33665:33665 +0.00011266336187471834 56751:56751 +0.00011266336187471834 32855:32855 +0.00011266336187471834 57439:57439 +0.00011266336187471834 35334:35334 +0.00011266336187471834 34144:34144 +0.00011266336187471834 56297:56297 +0.00011266336187471834 57398:57398 +0.00011266336187471834 56040:56040 +0.00011266336187471834 58601:58601 +0.00011266336187471834 60395:60395 +0.00011266336187471834 33236:33236 +0.00011266336187471834 57505:57505 +0.00011266336187471834 57471:57471 +0.00011266336187471834 60093:60093 +0.00011266336187471834 55809:55809 +0.00011266336187471834 35273:35273 +0.00011266336187471834 32856:32856 +0.00011266336187471834 34408:34408 +0.00011266336187471834 33586:33586 +0.00011266336187471834 35000:35000 +0.00011266336187471834 33113:33113 +0.00011266336187471834 59467:59467 +0.00011266336187471834 56995:56995 +0.00011266336187471834 56434:56434 +0.00011266336187471834 56344:56344 +0.00011266336187471834 56015:56015 +0.00011266336187471834 60045:60045 +0.00011266336187471834 59859:59859 +0.00011266336187471834 58634:58634 +0.00011266336187471834 34339:34339 +0.00011266336187471834 60096:60096 +0.00011266336187471834 59393:59393 +0.00011266336187471834 35464:35464 +0.00011266336187471834 58677:58677 +0.00011266336187471834 56704:56704 +0.00011266336187471834 56123:56123 +0.00011266336187471834 60884:60884 +0.00011266336187471834 58746:58746 +0.00011266336187471834 60186:60186 +0.00011266336187471834 56604:56604 +0.00011266336187471834 34464:34464 +0.00011266336187471834 34640:34640 +0.00011266336187471834 58833:58833 +0.00011266336187471834 57971:57971 +0.00011266336187471834 56696:56696 +0.00011266336187471834 33030:33030 +0.00011266336187471834 59016:59016 +0.00011266336187471834 33339:33339 +0.00011266336187471834 59888:59888 +0.00011266336187471834 34629:34629 +0.00011266336187471834 60340:60340 +0.00011266336187471834 34628:34628 +0.00011266336187471834 35250:35250 +0.00011266336187471834 59088:59088 +0.00011266336187471834 59833:59833 +0.00011266336187471834 58492:58492 +0.00011266336187471834 35116:35116 +0.00011266336187471834 55840:55840 +0.00011266336187471834 60328:60328 +0.00011266336187471834 59868:59868 +0.00011266336187471834 60680:60680 +0.00011266336187471834 57926:57926 +0.00011266336187471834 34122:34122 +0.00011266336187471834 59049:59049 +0.00011266336187471834 33888:33888 +0.00011266336187471834 33619:33619 +0.00011266336187471834 55806:55806 +0.00011266336187471834 59816:59816 +0.00011266336187471834 33893:33893 +0.00011266336187471834 60678:60678 +0.00011266336187471834 55846:55846 +0.00011266336187471834 34808:34808 +0.00011266336187471834 33967:33967 +0.00011266336187471834 34735:34735 +0.00011266336187471834 59365:59365 +0.00011266336187471834 34847:34847 +0.00011266336187471834 56002:56002 +0.00011266336187471834 33403:33403 +0.00011266336187471834 60702:60702 +0.00011266336187471834 58934:58934 +0.00011266336187471834 57466:57466 +0.00011266336187471834 57035:57035 +0.00011266336187471834 34970:34970 +0.00011266336187471834 59173:59173 +0.00011266336187471834 34514:34514 +0.00011266336187471834 59056:59056 +0.00011266336187471834 34583:34583 +0.00011266336187471834 59495:59495 +0.00011266336187471834 58937:58937 +0.00011266336187471834 56930:56930 +0.00011266336187471834 56001:56001 +0.00011266336187471834 60188:60188 +0.00011266336187471834 59640:59640 +0.00011266336187471834 57352:57352 +0.00011266336187471834 33748:33748 +0.00011266336187471834 33075:33075 +0.00011266336187471834 60343:60343 +0.00011266336187471834 60194:60194 +0.00011266336187471834 35157:35157 +0.00011266336187471834 58168:58168 +0.00011266336187471834 57904:57904 +0.00011266336187471834 34149:34149 +0.00011266336187471834 56130:56130 +0.00011266336187471834 34553:34553 +0.00011266336187471834 58994:58994 +0.00011266336187471834 58170:58170 +0.00011266336187471834 58804:58804 +0.00011266336187471834 59441:59441 +0.00011266336187471834 60686:60686 +0.00011266336187471834 60323:60323 +0.00011266336187471834 57553:57553 +0.00011266336187471834 33376:33376 +0.00011266336187471834 34357:34357 +0.00011266336187471834 34663:34663 +0.00011266336187471834 60165:60165 +0.00011266336187471834 56166:56166 +0.00011266336187471834 34586:34586 +0.00011266336187471834 60813:60813 +0.00011266336187471834 32977:32977 +0.00011266336187471834 33741:33741 +0.00011266336187471834 35013:35013 +0.00011266336187471834 33829:33829 +0.00011266336187471834 59907:59907 +0.00011266336187471834 34444:34444 +0.00011266336187471834 32844:32844 +0.00011266336187471834 56482:56482 +0.00011266336187471834 60383:60383 +0.00011266336187471834 60142:60142 +0.00011266336187471834 55970:55970 +0.00011266336187471834 56443:56443 +0.00011266336187471834 57139:57139 +0.00011266336187471834 35277:35277 +0.00011266336187471834 59220:59220 +0.00011266336187471834 57030:57030 +0.00011266336187471834 57718:57718 +0.00011266336187471834 32922:32922 +0.00011266336187471834 32983:32983 +0.00011266336187471834 58955:58955 +0.00011266336187471834 35046:35046 +0.00011266336187471834 33575:33575 +0.00011266336187471834 33034:33034 +0.00011266336187471834 34771:34771 +0.00011266336187471834 55876:55876 +0.00011266336187471834 56810:56810 +0.00011266336187471834 60067:60067 +0.00011266336187471834 59153:59153 +0.00011266336187471834 56322:56322 +0.00011266336187471834 34410:34410 +0.00011266336187471834 58255:58255 +0.00011266336187471834 33585:33585 +0.00011266336187471834 60047:60047 +0.00011266336187471834 56934:56934 +0.00011266336187471834 55630:55630 +0.00011266336187471834 56179:56179 +0.00011266336187471834 58426:58426 +0.00011266336187471834 33163:33163 +0.00011266336187471834 32880:32880 +0.00011266336187471834 33546:33546 +0.00011266336187471834 35504:35504 +0.00011266336187471834 55922:55922 +0.00011266336187471834 59443:59443 +0.00011266336187471834 60242:60242 +0.00011266336187471834 60335:60335 +0.00011266336187471834 58330:58330 +0.00011266336187471834 58145:58145 +0.00011266336187471834 56494:56494 +0.00011266336187471834 58673:58673 +0.00011266336187471834 60506:60506 +0.00011266336187471834 59958:59958 +0.00011266336187471834 34402:34402 +0.00011266336187471834 33334:33334 +0.00011266336187471834 34320:34320 +0.00011266336187471834 58329:58329 +0.00011266336187471834 60006:60006 +0.00011266336187471834 60654:60654 +0.00011266336187471834 57544:57544 +0.00011266336187471834 59401:59401 +0.00011266336187471834 59309:59309 +0.00011266336187471834 57036:57036 +0.00011266336187471834 35215:35215 +0.00011266336187471834 58032:58032 +0.00011266336187471834 56208:56208 +0.00011266336187471834 35072:35072 +0.00011266336187471834 60911:60911 +0.00011266336187471834 57175:57175 +0.00011266336187471834 33463:33463 +0.00011266336187471834 56404:56404 +0.00011266336187471834 33718:33718 +0.00011266336187471834 59764:59764 +0.00011266336187471834 57437:57437 +0.00011266336187471834 56646:56646 +0.00011266336187471834 58315:58315 +0.00011266336187471834 57341:57341 +0.00011266336187471834 34578:34578 +0.00011266336187471834 35263:35263 +0.00011266336187471834 34261:34261 +0.00011266336187471834 34301:34301 +0.00011266336187471834 34248:34248 +0.00011266336187471834 34078:34078 +0.00011266336187471834 58336:58336 +0.00011266336187471834 58258:58258 +0.00011266336187471834 34411:34411 +0.00011266336187471834 56621:56621 +0.00011266336187471834 55811:55811 +0.00011266336187471834 58992:58992 +0.00011266336187471834 34063:34063 +0.00011266336187471834 33513:33513 +0.00011266336187471834 59665:59665 +0.00011266336187471834 35305:35305 +0.00011266336187471834 34436:34436 +0.00011266336187471834 58584:58584 +0.00011266336187471834 55833:55833 +0.00011266336187471834 32796:32796 +0.00011266336187471834 58210:58210 +0.00011266336187471834 33831:33831 +0.00011266336187471834 59746:59746 +0.00011266336187471834 57271:57271 +0.00011266336187471834 33307:33307 +0.00011266336187471834 56403:56403 +0.00011266336187471834 57380:57380 +0.00011266336187471834 58398:58398 +0.00011266336187471834 33057:33057 +0.00011266336187471834 56720:56720 +0.00011266336187471834 58668:58668 +0.00011266336187471834 59677:59677 +0.00011266336187471834 58670:58670 +0.00011266336187471834 35294:35294 +0.00011266336187471834 34835:34835 +0.00011266336187471834 33597:33597 +0.00011266336187471834 57528:57528 +0.00011266336187471834 57001:57001 +0.00011266336187471834 55763:55763 +0.00011266336187471834 59650:59650 +0.00011266336187471834 35424:35424 +0.00011266336187471834 57834:57834 +0.00011266336187471834 33503:33503 +0.00011266336187471834 60615:60615 +0.00011266336187471834 34879:34879 +0.00011266336187471834 33910:33910 +0.00011266336187471834 59486:59486 +0.00011266336187471834 57643:57643 +0.00011266336187471834 34600:34600 +0.00011266336187471834 32963:32963 +0.00011266336187471834 56237:56237 +0.00011266336187471834 55781:55781 +0.00011266336187471834 56667:56667 +0.00011266336187471834 59912:59912 +0.00011266336187471834 55920:55920 +0.00011266336187471834 60579:60579 +0.00011266336187471834 34999:34999 +0.00011266336187471834 33103:33103 +0.00011266336187471834 58918:58918 +0.00011266336187471834 57941:57941 +0.00011266336187471834 60258:60258 +0.00011266336187471834 57198:57198 +0.00011266336187471834 58891:58891 +0.00011266336187471834 55653:55653 +0.00011266336187471834 60103:60103 +0.00011266336187471834 59315:59315 +0.00011266336187471834 57578:57578 +0.00011266336187471834 56228:56228 +0.00011266336187471834 58926:58926 +0.00011266336187471834 60263:60263 +0.00011266336187471834 33491:33491 +0.00011266336187471834 59962:59962 +0.00011266336187471834 60936:60936 +0.00011266336187471834 59496:59496 +0.00011266336187471834 60881:60881 +0.00011266336187471834 58682:58682 +0.00011266336187471834 57720:57720 +0.00011266336187471834 60173:60173 +0.00011266336187471834 59194:59194 +0.00011266336187471834 58532:58532 +0.00011266336187471834 57410:57410 +0.00011266336187471834 57117:57117 +0.00011266336187471834 60621:60621 +0.00011266336187471834 57240:57240 +0.00011266336187471834 57210:57210 +0.00011266336187471834 58942:58942 +0.00011266336187471834 59995:59995 +0.00011266336187471834 58015:58015 +0.00011266336187471834 58556:58556 +0.00011266336187471834 58160:58160 +0.00011266336187471834 57104:57104 +0.00011266336187471834 60054:60054 +0.00011266336187471834 60841:60841 +0.00011266336187471834 60149:60149 +0.00011266336187471834 58488:58488 +0.00011266336187471834 55862:55862 +0.00011266336187471834 33880:33880 +0.00011266336187471834 59684:59684 +0.00011266336187471834 35278:35278 +0.00011266336187471834 57302:57302 +0.00011266336187471834 57002:57002 +0.00011266336187471834 32783:32783 +0.00011266336187471834 59229:59229 +0.00011266336187471834 57399:57399 +0.00011266336187471834 35275:35275 +0.00011266336187471834 57541:57541 +0.00011266336187471834 56869:56869 +0.00011266336187471834 59366:59366 +0.00011266336187471834 58498:58498 +0.00011266336187471834 58141:58141 +0.00011266336187471834 56008:56008 +0.00011266336187471834 60390:60390 +0.00011266336187471834 32832:32832 +0.00011266336187471834 33218:33218 +0.00011266336187471834 34287:34287 +0.00011266336187471834 58991:58991 +0.00011266336187471834 35309:35309 +0.00011266336187471834 34227:34227 +0.00011266336187471834 34158:34158 +0.00011266336187471834 60696:60696 +0.00011266336187471834 56953:56953 +0.00011266336187471834 33965:33965 +0.00011266336187471834 58202:58202 +0.00011266336187471834 60556:60556 +0.00011266336187471834 58759:58759 +0.00011266336187471834 57134:57134 +0.00011266336187471834 56562:56562 +0.00011266336187471834 57448:57448 +0.00011266336187471834 57041:57041 +0.00011266336187471834 56118:56118 +0.00011266336187471834 55798:55798 +0.00011266336187471834 34825:34825 +0.00011266336187471834 58043:58043 +0.00011266336187471834 57975:57975 +0.00011266336187471834 55875:55875 +0.00011266336187471834 59453:59453 +0.00011266336187471834 59696:59696 +0.00011266336187471834 56250:56250 +0.00011266336187471834 56903:56903 +0.00011266336187471834 60226:60226 +0.00011266336187471834 56450:56450 +0.00011266336187471834 59210:59210 +0.00011266336187471834 58970:58970 +0.00011266336187471834 34783:34783 +0.00011266336187471834 34300:34300 +0.00011266336187471834 60070:60070 +0.00011266336187471834 33555:33555 +0.00011266336187471834 33413:33413 +0.00011266336187471834 56549:56549 +0.00011266336187471834 32807:32807 +0.00011266336187471834 59410:59410 +0.00011266336187471834 56803:56803 +0.00011266336187471834 56874:56874 +0.00011266336187471834 34314:34314 +0.00011266336187471834 56993:56993 +0.00011266336187471834 33930:33930 +0.00011266336187471834 59576:59576 +0.00011266336187471834 57042:57042 +0.00011266336187471834 32899:32899 +0.00011266336187471834 55735:55735 +0.00011266336187471834 34618:34618 +0.00011266336187471834 60865:60865 +0.00011266336187471834 33591:33591 +0.00011266336187471834 35043:35043 +0.00011266336187471834 33759:33759 +0.00011266336187471834 60743:60743 +0.00011266336187471834 59817:59817 +0.00011266336187471834 56755:56755 +0.00011266336187471834 59637:59637 +0.00011266336187471834 59307:59307 +0.00011266336187471834 60182:60182 +0.00011266336187471834 59162:59162 +0.00011266336187471834 57719:57719 +0.00011266336187471834 35126:35126 +0.00011266336187471834 35101:35101 +0.00011266336187471834 35042:35042 +0.00011266336187471834 58821:58821 +0.00011266336187471834 32953:32953 +0.00011266336187471834 56360:56360 +0.00011266336187471834 33492:33492 +0.00011266336187471834 58557:58557 +0.00011266336187471834 33850:33850 +0.00011266336187471834 57254:57254 +0.00011266336187471834 59367:59367 +0.00011266336187471834 35392:35392 +0.00011266336187471834 34605:34605 +0.00011266336187471834 60310:60310 +0.00011266336187471834 56274:56274 +0.00011266336187471834 56395:56395 +0.00011266336187471834 56239:56239 +0.00011266336187471834 57445:57445 +0.00011266336187471834 58693:58693 +0.00011266336187471834 58679:58679 +0.00011266336187471834 58266:58266 +0.00011266336187471834 60051:60051 +0.00011266336187471834 59613:59613 +0.00011266336187471834 55769:55769 +0.00011266336187471834 60737:60737 +0.00011266336187471834 58363:58363 +0.00011266336187471834 56597:56597 +0.00011266336187471834 34418:34418 +0.00011266336187471834 58371:58371 +0.00011266336187471834 33366:33366 +0.00011266336187471834 57978:57978 +0.00011266336187471834 56205:56205 +0.00011266336187471834 60437:60437 +0.00011266336187471834 59602:59602 +0.00011266336187471834 58727:58727 +0.00011266336187471834 33868:33868 +0.00011266336187471834 60705:60705 +0.00011266336187471834 60657:60657 +0.00011266336187471834 59184:59184 +0.00011266336187471834 58314:58314 +0.00011266336187471834 57748:57748 +0.00011266336187471834 60424:60424 +0.00011266336187471834 33270:33270 +0.00011266336187471834 33861:33861 +0.00011266336187471834 58086:58086 +0.00011266336187471834 34749:34749 +0.00011266336187471834 56905:56905 +0.00011266336187471834 57816:57816 +0.00011266336187471834 32845:32845 +0.00011266336187471834 59389:59389 +0.00011266336187471834 56949:56949 +0.00011266336187471834 56388:56388 +0.00011266336187471834 57353:57353 +0.00011266336187471834 59344:59344 +0.00011266336187471834 57496:57496 +0.00011266336187471834 32850:32850 +0.00011266336187471834 58910:58910 +0.00011266336187471834 60736:60736 +0.00011266336187471834 34627:34627 +0.00011266336187471834 56057:56057 +0.00011266336187471834 56836:56836 +0.00011266336187471834 58383:58383 +0.00011266336187471834 56054:56054 +0.00011266336187471834 58221:58221 +0.00011266336187471834 57714:57714 +0.00011266336187471834 57487:57487 +0.00011266336187471834 56441:56441 +0.00011266336187471834 59564:59564 +0.00011266336187471834 56082:56082 +0.00011266336187471834 34523:34523 +0.00011266336187471834 59138:59138 +0.00011266336187471834 34022:34022 +0.00011266336187471834 60782:60782 +0.00011266336187471834 60359:60359 +0.00011266336187471834 34696:34696 +0.00011266336187471834 57671:57671 +0.00011266336187471834 55628:55628 +0.00011266336187471834 59436:59436 +0.00011266336187471834 59224:59224 +0.00011266336187471834 56350:56350 +0.00011266336187471834 57467:57467 +0.00011266336187471834 32872:32872 +0.00011266336187471834 58593:58593 +0.00011266336187471834 34964:34964 +0.00011266336187471834 33988:33988 +0.00011266336187471834 33697:33697 +0.00011266336187471834 56147:56147 +0.00011266336187471834 33071:33071 +0.00011266336187471834 32933:32933 +0.00011266336187471834 59590:59590 +0.00011266336187471834 56671:56671 +0.00011266336187471834 58740:58740 +0.00011266336187471834 57802:57802 +0.00011266336187471834 56484:56484 +0.00011266336187471834 33807:33807 +0.00011266336187471834 59087:59087 +0.00011266336187471834 58178:58178 +0.00011266336187471834 56927:56927 +0.00011266336187471834 33353:33353 +0.00011266336187471834 56912:56912 +0.00011266336187471834 55777:55777 +0.00011266336187471834 35057:35057 +0.00011266336187471834 60630:60630 +0.00011266336187471834 57279:57279 +0.00011266336187471834 35318:35318 +0.00011266336187471834 60462:60462 +0.00011266336187471834 35167:35167 +0.00011266336187471834 33201:33201 +0.00011266336187471834 58423:58423 +0.00011266336187471834 33009:33009 +0.00011266336187471834 35559:35559 +0.00011266336187471834 33020:33020 +0.00011266336187471834 60308:60308 +0.00011266336187471834 35306:35306 +0.00011266336187471834 33189:33189 +0.00011266336187471834 59251:59251 +0.00011266336187471834 57907:57907 +0.00011266336187471834 35185:35185 +0.00011266336187471834 33523:33523 +0.00011266336187471834 60211:60211 +0.00011266336187471834 34635:34635 +0.00011266336187471834 59606:59606 +0.00011266336187471834 60312:60312 +0.00011266336187471834 59065:59065 +0.00011266336187471834 56981:56981 +0.00011266336187471834 55971:55971 +0.00011266336187471834 33994:33994 +0.00011266336187471834 33549:33549 +0.00011266336187471834 60159:60159 +0.00011266336187471834 58400:58400 +0.00011266336187471834 35346:35346 +0.00011266336187471834 33286:33286 +0.00011266336187471834 60606:60606 +0.00011266336187471834 60119:60119 +0.00011266336187471834 58205:58205 +0.00011266336187471834 35266:35266 +0.00011266336187471834 60295:60295 +0.00011266336187471834 60436:60436 +0.00011266336187471834 57079:57079 +0.00011266336187471834 33451:33451 +0.00011266336187471834 32966:32966 +0.00011266336187471834 32959:32959 +0.00011266336187471834 32785:32785 +0.00011266336187471834 59903:59903 +0.00011266336187471834 58494:58494 +0.00011266336187471834 55895:55895 +0.00011266336187471834 34881:34881 +0.00011266336187471834 60658:60658 +0.00011266336187471834 59857:59857 +0.00011266336187471834 35451:35451 +0.00011266336187471834 57568:57568 +0.00011266336187471834 57854:57854 +0.00011266336187471834 57674:57674 +0.00011266336187471834 60244:60244 +0.00011266336187471834 58973:58973 +0.00011266336187471834 58769:58769 +0.00011266336187471834 57704:57704 +0.00011266336187471834 58686:58686 +0.00011266336187471834 34972:34972 +0.00011266336187471834 32957:32957 +0.00011266336187471834 58285:58285 +0.00011266336187471834 56659:56659 +0.00011266336187471834 32865:32865 +0.00011266336187471834 60592:60592 +0.00011266336187471834 57987:57987 +0.00011266336187471834 56571:56571 +0.00011266336187471834 60564:60564 +0.00011266336187471834 58831:58831 +0.00011266336187471834 34489:34489 +0.00011266336187471834 34373:34373 +0.00011266336187471834 33342:33342 +0.00011266336187471834 59254:59254 +0.00011266336187471834 60161:60161 +0.00011266336187471834 57074:57074 +0.00011266336187471834 33390:33390 +0.00011266336187471834 33304:33304 +0.00011266336187471834 33118:33118 +0.00011266336187471834 33646:33646 +0.00011266336187471834 60157:60157 +0.00011266336187471834 56081:56081 +0.00011266336187471834 60207:60207 +0.00011266336187471834 60932:60932 +0.00011266336187471834 34651:34651 +0.00011266336187471834 33559:33559 +0.00011266336187471834 57775:57775 +0.00011266336187471834 60252:60252 +0.00011266336187471834 34326:34326 +0.00011266336187471834 33024:33024 +0.00011266336187471834 59074:59074 +0.00011266336187471834 57581:57581 +0.00011266336187471834 33162:33162 +0.00011266336187471834 55785:55785 +0.00011266336187471834 59737:59737 +0.00011266336187471834 35119:35119 +0.00011266336187471834 58345:58345 +0.00011266336187471834 57734:57734 +0.00011266336187471834 35301:35301 +0.00011266336187471834 35207:35207 +0.00011266336187471834 33344:33344 +0.00011266336187471834 57891:57891 +0.00011266336187471834 59073:59073 +0.00011266336187471834 57832:57832 +0.00011266336187471834 59425:59425 +0.00011266336187471834 58861:58861 +0.00011266336187471834 33048:33048 +0.00011266336187471834 56225:56225 +0.00011266336187471834 57038:57038 +0.00011266336187471834 34263:34263 +0.00011266336187471834 56569:56569 +0.00011266336187471834 58063:58063 +0.00011266336187471834 58419:58419 +0.00011266336187471834 35420:35420 +0.00011266336187471834 56409:56409 +0.00011266336187471834 35237:35237 +0.00011266336187471834 57478:57478 +0.00011266336187471834 57078:57078 +0.00011266336187471834 35077:35077 +0.00011266336187471834 34611:34611 +0.00011266336187471834 33530:33530 +0.00011266336187471834 33746:33746 +0.00011266336187471834 59680:59680 +0.00011266336187471834 34871:34871 +0.00011266336187471834 59193:59193 +0.00011266336187471834 58755:58755 +0.00011266336187471834 33301:33301 +0.00011266336187471834 33387:33387 +0.00011266336187471834 59031:59031 +0.00011266336187471834 55632:55632 +0.00011266336187471834 33542:33542 +0.00011266336187471834 57644:57644 +0.00011266336187471834 33514:33514 +0.00011266336187471834 58072:58072 +0.00011266336187471834 57033:57033 +0.00011266336187471834 35469:35469 +0.00011266336187471834 57736:57736 +0.00011266336187471834 58884:58884 +0.00011266336187471834 60421:60421 +0.00011266336187471834 58683:58683 +0.00011266336187471834 35329:35329 +0.00011266336187471834 33900:33900 +0.00011266336187471834 60502:60502 +0.00011266336187471834 33172:33172 +0.00011266336187471834 60285:60285 +0.00011266336187471834 35450:35450 +0.00011266336187471834 59916:59916 +0.00011266336187471834 33308:33308 +0.00011266336187471834 33040:33040 +0.00011266336187471834 60086:60086 +0.00011266336187471834 57260:57260 +0.00011266336187471834 33265:33265 +0.00011266336187471834 59507:59507 +0.00011266336187471834 35430:35430 +0.00011266336187471834 33174:33174 +0.00011266336187471834 60734:60734 +0.00011266336187471834 60068:60068 +0.00011266336187471834 58468:58468 +0.00011266336187471834 58820:58820 +0.00011266336187471834 35290:35290 +0.00011266336187471834 57222:57222 +0.00011266336187471834 56705:56705 +0.00011266336187471834 33338:33338 +0.00011266336187471834 59026:59026 +0.00011266336187471834 33848:33848 +0.00011266336187471834 56789:56789 +0.00011266336187471834 58126:58126 +0.00011266336187471834 33731:33731 +0.00011266336187471834 33670:33670 +0.00011266336187471834 32846:32846 +0.00011266336187471834 59269:59269 +0.00011266336187471834 33949:33949 +0.00011266336187471834 33830:33830 +0.00011266336187471834 35493:35493 +0.00011266336187471834 59089:59089 +0.00011266336187471834 33315:33315 +0.00011266336187471834 58323:58323 +0.00011266336187471834 56976:56976 +0.00011266336187471834 55900:55900 +0.00011266336187471834 33595:33595 +0.00011266336187471834 59711:59711 +0.00011266336187471834 57753:57753 +0.00011266336187471834 34834:34834 +0.00011266336187471834 58010:58010 +0.00011266336187471834 57157:57157 +0.00011266336187471834 56257:56257 +0.00011266336187471834 58802:58802 +0.00011266336187471834 58544:58544 +0.00011266336187471834 60542:60542 +0.00011266336187471834 59133:59133 +0.00011266336187471834 60121:60121 +0.00011266336187471834 56430:56430 +0.00011266336187471834 32773:32773 +0.00011266336187471834 56217:56217 +0.00011266336187471834 57131:57131 +0.00011266336187471834 55841:55841 +0.00011266336187471834 34563:34563 +0.00011266336187471834 33437:33437 +0.00011266336187471834 60381:60381 +0.00011266336187471834 34842:34842 +0.00011266336187471834 60346:60346 +0.00011266336187471834 60088:60088 +0.00011266336187471834 34077:34077 +0.00011266336187471834 58904:58904 +0.00011266336187471834 35308:35308 +0.00011266336187471834 33803:33803 +0.00011266336187471834 33199:33199 +0.00011266336187471834 57831:57831 +0.00011266336187471834 33318:33318 +0.00011266336187471834 32999:32999 +0.00011266336187471834 55765:55765 +0.00011266336187471834 33919:33919 +0.00011266336187471834 56985:56985 +0.00011266336187471834 56473:56473 +0.00011266336187471834 35115:35115 +0.00011266336187471834 58640:58640 +0.00011266336187471834 34684:34684 +0.00011266336187471834 33230:33230 +0.00011266336187471834 60979:60979 +0.00011266336187471834 33402:33402 +0.00011266336187471834 59886:59886 +0.00011266336187471834 58940:58940 +0.00011266336187471834 34337:34337 +0.00011266336187471834 59279:59279 +0.00011266336187471834 57645:57645 +0.00011266336187471834 56278:56278 +0.00011266336187471834 57154:57154 +0.00011266336187471834 60975:60975 +0.00011266336187471834 34545:34545 +0.00011266336187471834 60203:60203 +0.00011266336187471834 59462:59462 +0.00011266336187471834 58835:58835 +0.00011266336187471834 33592:33592 +0.00011266336187471834 58895:58895 +0.00011266336187471834 34655:34655 +0.00011266336187471834 57747:57747 +0.00011266336187471834 57634:57634 +0.00011266336187471834 58988:58988 +0.00011266336187471834 33062:33062 +0.00011266336187471834 60921:60921 +0.00011266336187471834 56189:56189 +0.00011266336187471834 34702:34702 +0.00011266336187471834 33421:33421 +0.00011266336187471834 33501:33501 +0.00011266336187471834 55937:55937 +0.00011266336187471834 39733:39733 +0.00011266336187471834 56964:56964 +0.00011266336187471834 58166:58166 +0.00011266336187471834 55641:55641 +0.00011266336187471834 60300:60300 +0.00011266336187471834 34741:34741 +0.00011266336187471834 55663:55663 +0.00011266336187471834 32813:32813 +0.00011266336187471834 56425:56425 +0.00011266336187471834 34404:34404 +0.00011266336187471834 60452:60452 +0.00011266336187471834 60475:60475 +0.00011266336187471834 35416:35416 +0.00011266336187471834 34189:34189 +0.00011266336187471834 33028:33028 +0.00011266336187471834 59844:59844 +0.00011266336187471834 60448:60448 +0.00011266336187471834 32852:32852 +0.00011266336187471834 57363:57363 +0.00011266336187471834 57242:57242 +0.00011266336187471834 34799:34799 +0.00011266336187471834 32840:32840 +0.00011266336187471834 60118:60118 +0.00011266336187471834 34776:34776 +0.00011266336187471834 60933:60933 +0.00011266336187471834 59627:59627 +0.00011266336187471834 58081:58081 +0.00011266336187471834 59938:59938 +0.00011266336187471834 58067:58067 +0.00011266336187471834 57084:57084 +0.00011266336187471834 58133:58133 +0.00011266336187471834 34472:34472 +0.00011266336187471834 34674:34674 +0.00011266336187471834 59461:59461 +0.00011266336187471834 35335:35335 +0.00011266336187471834 57579:57579 +0.00011266336187471834 57430:57430 +0.00011266336187471834 56645:56645 +0.00011266336187471834 56289:56289 +0.00011266336187471834 34646:34646 +0.00011266336187471834 58827:58827 +0.00011266336187471834 56043:56043 +0.00011266336187471834 34932:34932 +0.00011266336187471834 34018:34018 +0.00011266336187471834 32984:32984 +0.00011266336187471834 59946:59946 +0.00011266336187471834 59198:59198 +0.00011266336187471834 59596:59596 +0.00011266336187471834 58424:58424 +0.00011266336187471834 59989:59989 +0.00011266336187471834 59614:59614 +0.00011266336187471834 56407:56407 +0.00011266336187471834 56547:56547 +0.00011266336187471834 58107:58107 +0.00011266336187471834 57015:57015 +0.00011266336187471834 34493:34493 +0.00011266336187471834 32834:32834 +0.00011266336187471834 57339:57339 +0.00011266336187471834 59783:59783 +0.00011266336187471834 59329:59329 +0.00011266336187471834 35339:35339 +0.00011266336187471834 60411:60411 +0.00011266336187471834 58703:58703 +0.00011266336187471834 55744:55744 +0.00011266336187471834 32991:32991 +0.00011266336187471834 58651:58651 +0.00011266336187471834 34756:34756 +0.00011266336187471834 60717:60717 +0.00011266336187471834 33101:33101 +0.00011266336187471834 57796:57796 +0.00011266336187471834 34977:34977 +0.00011266336187471834 56879:56879 +0.00011266336187471834 60505:60505 +0.00011266336187471834 58518:58518 +0.00011266336187471834 33405:33405 +0.00011266336187471834 33615:33615 +0.00011266336187471834 35011:35011 +0.00011266336187471834 60647:60647 +0.00011266336187471834 59806:59806 +0.00011266336187471834 60183:60183 +0.00011266336187471834 34011:34011 +0.00011266336187471834 33631:33631 +0.00011266336187471834 60757:60757 +0.00011266336187471834 58571:58571 +0.00011266336187471834 58227:58227 +0.00011266336187471834 34128:34128 +0.00011266336187471834 33580:33580 +0.00011266336187471834 57438:57438 +0.00011266336187471834 35519:35519 +0.00011266336187471834 58294:58294 +0.00011266336187471834 58863:58863 +0.00011266336187471834 57295:57295 +0.00011266336187471834 59799:59799 +0.00011266336187471834 58120:58120 +0.00011266336187471834 33870:33870 +0.00011266336187471834 57019:57019 +0.00011266336187471834 33824:33824 +0.00011266336187471834 55930:55930 +0.00011266336187471834 58698:58698 +0.00011266336187471834 56587:56587 +0.00011266336187471834 35040:35040 +0.00011266336187471834 57330:57330 +0.00011266336187471834 35190:35190 +0.00011266336187471834 58289:58289 +0.00011266336187471834 34748:34748 +0.00011266336187471834 33408:33408 +0.00011266336187471834 35361:35361 +0.00011266336187471834 59295:59295 +0.00011266336187471834 60803:60803 +0.00011266336187471834 58896:58896 +0.00011266336187471834 55694:55694 +0.00011266336187471834 33669:33669 +0.00011266336187471834 59909:59909 +0.00011266336187471834 34477:34477 +0.00011266336187471834 57394:57394 +0.00011266336187471834 57413:57413 +0.00011266336187471834 33678:33678 +0.00011266336187471834 57375:57375 +0.00011266336187471834 56847:56847 +0.00011266336187471834 57965:57965 +0.00011266336187471834 58793:58793 +0.00011266336187471834 57370:57370 +0.00011266336187471834 56962:56962 +0.00011266336187471834 32884:32884 +0.00011266336187471834 56476:56476 +0.00011266336187471834 56390:56390 +0.00011266336187471834 55771:55771 +0.00011266336187471834 33792:33792 +0.00011266336187471834 33673:33673 +0.00011266336187471834 33325:33325 +0.00011266336187471834 59361:59361 +0.00011266336187471834 56265:56265 +0.00011266336187471834 32853:32853 +0.00011266336187471834 60418:60418 +0.00011266336187471834 56973:56973 +0.00011266336187471834 34346:34346 +0.00011266336187471834 58001:58001 +0.00011266336187471834 34181:34181 +0.00011266336187471834 56321:56321 +0.00011266336187471834 55710:55710 +0.00011266336187471834 56198:56198 +0.00011266336187471834 60122:60122 +0.00011266336187471834 34046:34046 +0.00011266336187471834 33903:33903 +0.00011266336187471834 35506:35506 +0.00011266336187471834 32864:32864 +0.00011266336187471834 57622:57622 +0.00011266336187471834 56401:56401 +0.00011266336187471834 58691:58691 +0.00011266336187471834 58165:58165 +0.00011266336187471834 59880:59880 +0.00011266336187471834 58856:58856 +0.00011266336187471834 58645:58645 +0.00011266336187471834 57390:57390 +0.00011266336187471834 60488:60488 +0.00011266336187471834 59270:59270 +0.00011266336187471834 56699:56699 +0.00011266336187471834 56340:56340 +0.00011266336187471834 34071:34071 +0.00011266336187471834 57276:57276 +0.00011266336187471834 32811:32811 +0.00011266336187471834 34004:34004 +0.00011266336187471834 57296:57296 +0.00011266336187471834 57546:57546 +0.00011266336187471834 56492:56492 +0.00011266336187471834 34354:34354 +0.00011266336187471834 32776:32776 +0.00011266336187471834 59765:59765 +0.00011266336187471834 59675:59675 +0.00011266336187471834 33448:33448 +0.00011266336187471834 33212:33212 +0.00011266336187471834 32798:32798 +0.00011266336187471834 55741:55741 +0.00011266336187471834 60772:60772 +0.00011266336187471834 56763:56763 +0.00011266336187471834 55754:55754 +0.00011266336187471834 34895:34895 +0.00011266336187471834 60425:60425 +0.00011266336187471834 56842:56842 +0.00011266336187471834 33241:33241 +0.00011266336187471834 60639:60639 +0.00011266336187471834 56083:56083 +0.00011266336187471834 57334:57334 +0.00011266336187471834 34985:34985 +0.00011266336187471834 55965:55965 +0.00011266336187471834 35179:35179 +0.00011266336187471834 56505:56505 +0.00011266336187471834 56106:56106 +0.00011266336187471834 35201:35201 +0.00011266336187471834 59776:59776 +0.00011266336187471834 56708:56708 +0.00011266336187471834 34897:34897 +0.00011266336187471834 56795:56795 +0.00011266336187471834 32829:32829 +0.00011266336187471834 60057:60057 +0.00011266336187471834 56277:56277 +0.00011266336187471834 55695:55695 +0.00011266336187471834 34455:34455 +0.00011266336187471834 58358:58358 +0.00011266336187471834 56012:56012 +0.00011266336187471834 33412:33412 +0.00011266336187471834 33790:33790 +0.00011266336187471834 60787:60787 +0.00011266336187471834 57631:57631 +0.00011266336187471834 56035:56035 +0.00011266336187471834 56545:56545 +0.00011266336187471834 57414:57414 +0.00011266336187471834 59612:59612 +0.00011266336187471834 60008:60008 +0.00011266336187471834 33105:33105 +0.00011266336187471834 60255:60255 +0.00011266336187471834 34070:34070 +0.00011266336187471834 34900:34900 +0.00011266336187471834 33553:33553 +0.00011266336187471834 33372:33372 +0.00011266336187471834 33001:33001 +0.00011266336187471834 59083:59083 +0.00011266336187471834 35147:35147 +0.00011266336187471834 33708:33708 +0.00011266336187471834 34365:34365 +0.00011266336187471834 34168:34168 +0.00011266336187471834 34030:34030 +0.00011266336187471834 60861:60861 +0.00011266336187471834 59865:59865 +0.00011266336187471834 56157:56157 +0.00011266336187471834 33282:33282 +0.00011266336187471834 59537:59537 +0.00011266336187471834 58320:58320 +0.00011266336187471834 59472:59472 +0.00011266336187471834 57637:57637 +0.00011266336187471834 35295:35295 +0.00011266336187471834 60379:60379 +0.00011266336187471834 57251:57251 +0.00011266336187471834 56775:56775 +0.00011266336187471834 55725:55725 +0.00011266336187471834 58299:58299 +0.00011266336187471834 33435:33435 +0.00011266336187471834 58837:58837 +0.00011266336187471834 60132:60132 +0.00011266336187471834 58883:58883 +0.00011266336187471834 60497:60497 +0.00011266336187471834 58434:58434 +0.00011266336187471834 57206:57206 +0.00011266336187471834 60420:60420 +0.00011266336187471834 58966:58966 +0.00011266336187471834 56761:56761 +0.00011266336187471834 56825:56825 +0.00011266336187471834 34432:34432 +0.00011266336187471834 58373:58373 +0.00011266336187471834 34125:34125 +0.00011266336187471834 56044:56044 +0.00011266336187471834 56856:56856 +0.00011266336187471834 59141:59141 +0.00011266336187471834 58756:58756 +0.00011266336187471834 33015:33015 +0.00011266336187471834 33765:33765 +0.00011266336187471834 57873:57873 +0.00011266336187471834 60126:60126 +0.00011266336187471834 59822:59822 +0.00011266336187471834 59145:59145 +0.00011266336187471834 59608:59608 +0.00011266336187471834 34833:34833 +0.00011266336187471834 34667:34667 +0.00011266336187471834 60597:60597 +0.00011266336187471834 58077:58077 +0.00011266336187471834 55878:55878 +0.00011266336187471834 58435:58435 +0.00011266336187471834 57292:57292 +0.00011266336187471834 56112:56112 +0.00011266336187471834 58579:58579 +0.00011266336187471834 56135:56135 +0.00011266336187471834 57900:57900 +0.00011266336187471834 35463:35463 +0.00011266336187471834 57866:57866 +0.00011266336187471834 34059:34059 +0.00011266336187471834 55675:55675 +0.00011266336187471834 33191:33191 +0.00011266336187471834 60274:60274 +0.00011266336187471834 33419:33419 +0.00011266336187471834 35247:35247 +0.00011266336187471834 34043:34043 +0.00011266336187471834 59338:59338 +0.00011266336187471834 59600:59600 +0.00011266336187471834 58257:58257 +0.00011266336187471834 60261:60261 +0.00011266336187471834 58750:58750 +0.00011266336187471834 58572:58572 +0.00011266336187471834 35148:35148 +0.00011266336187471834 59492:59492 +0.00011266336187471834 35378:35378 +0.00011266336187471834 56302:56302 +0.00011266336187471834 55779:55779 +0.00011266336187471834 33380:33380 +0.00011266336187471834 57173:57173 +0.00011266336187471834 33330:33330 +0.00011266336187471834 60866:60866 +0.00011266336187471834 60661:60661 +0.00011266336187471834 34405:34405 +0.00011266336187471834 58020:58020 +0.00011266336187471834 56246:56246 +0.00011266336187471834 56387:56387 +0.00011266336187471834 34697:34697 +0.00011266336187471834 33060:33060 +0.00011266336187471834 56086:56086 +0.00011266336187471834 58271:58271 +0.00011266336187471834 57256:57256 +0.00011266336187471834 56165:56165 +0.00011266336187471834 57991:57991 +0.00011266336187471834 57151:57151 +0.00011266336187471834 59705:59705 +0.00011266336187471834 34626:34626 +0.00011266336187471834 55851:55851 +0.00011266336187471834 35139:35139 +0.00011266336187471834 33548:33548 +0.00011266336187471834 56694:56694 +0.00011266336187471834 60401:60401 +0.00011266336187471834 35360:35360 +0.00011266336187471834 34192:34192 +0.00011266336187471834 60399:60399 +0.00011266336187471834 33521:33521 +0.00011266336187471834 56379:56379 +0.00011266336187471834 34179:34179 +0.00011266336187471834 57540:57540 +0.00011266336187471834 33942:33942 +0.00011266336187471834 58471:58471 +0.00011266336187471834 55953:55953 +0.00011266336187471834 58600:58600 +0.00011266336187471834 57395:57395 +0.00011266336187471834 33786:33786 +0.00011266336187471834 57329:57329 +0.00011266336187471834 33641:33641 +0.00011266336187471834 58311:58311 +0.00011266336187471834 60800:60800 +0.00011266336187471834 60749:60749 +0.00011266336187471834 60670:60670 +0.00011266336187471834 56870:56870 +0.00011266336187471834 56909:56909 +0.00011266336187471834 57713:57713 +0.00011266336187471834 34769:34769 +0.00011266336187471834 57780:57780 +0.00011266336187471834 56730:56730 +0.00011266336187471834 57993:57993 +0.00011266336187471834 35536:35536 +0.00011266336187471834 55824:55824 +0.00011266336187471834 60501:60501 +0.00011266336187471834 59330:59330 +0.00011266336187471834 35523:35523 +0.00011266336187471834 35093:35093 +0.00011266336187471834 34700:34700 +0.00011266336187471834 60794:60794 +0.00011266336187471834 57882:57882 +0.00011266336187471834 57820:57820 +0.00011266336187471834 34953:34953 +0.00011266336187471834 34321:34321 +0.00011266336187471834 58917:58917 +0.00011266336187471834 35196:35196 +0.00011266336187471834 59060:59060 +0.00011266336187471834 35560:35560 +0.00011266336187471834 56243:56243 +0.00011266336187471834 60266:60266 +0.00011266336187471834 56888:56888 +0.00011266336187471834 59738:59738 +0.00011266336187471834 34465:34465 +0.00011266336187471834 34505:34505 +0.00011266336187471834 33284:33284 +0.00011266336187471834 35150:35150 +0.00011266336187471834 56576:56576 +0.00011266336187471834 33952:33952 +0.00011266336187471834 58763:58763 +0.00011266336187471834 35279:35279 +0.00011266336187471834 57324:57324 +0.00011266336187471834 60805:60805 +0.00011266336187471834 59159:59159 +0.00011266336187471834 56090:56090 +0.00011266336187471834 58796:58796 +0.00011266336187471834 57200:57200 +0.00011266336187471834 34555:34555 +0.00011266336187471834 59852:59852 +0.00011266336187471834 34774:34774 +0.00011266336187471834 55611:55611 +0.00011266336187471834 59605:59605 +0.00011266336187471834 57560:57560 +0.00011266336187471834 56038:56038 +0.00011266336187471834 58055:58055 +0.00011266336187471834 57999:57999 +0.00011266336187471834 56607:56607 +0.00011266336187471834 55943:55943 +0.00011266336187471834 55631:55631 +0.00011266336187471834 33250:33250 +0.00011266336187471834 35529:35529 +0.00011266336187471834 35482:35482 +0.00011266336187471834 34529:34529 +0.00011266336187471834 56915:56915 +0.00011266336187471834 34099:34099 +0.00011266336187471834 35182:35182 +0.00011266336187471834 56872:56872 +0.00011266336187471834 60507:60507 +0.00011266336187471834 59910:59910 +0.00011266336187471834 35020:35020 +0.00011266336187471834 59231:59231 +0.00011266336187471834 58860:58860 +0.00011266336187471834 59363:59363 +0.00011266336187471834 58040:58040 +0.00011266336187471834 58085:58085 +0.00011266336187471834 58260:58260 +0.00011266336187471834 57000:57000 +0.00011266336187471834 35051:35051 +0.00011266336187471834 34332:34332 +0.00011266336187471834 34788:34788 +0.00011266336187471834 60147:60147 +0.00011266336187471834 60527:60527 +0.00011266336187471834 59030:59030 +0.00011266336187471834 57506:57506 +0.00011266336187471834 58180:58180 +0.00011266336187471834 33682:33682 +0.00011266336187471834 33938:33938 +0.00011266336187471834 57174:57174 +0.00011266336187471834 57283:57283 +0.00011266336187471834 33571:33571 +0.00011266336187471834 59952:59952 +0.00011266336187471834 58964:58964 +0.00011266336187471834 57171:57171 +0.00011266336187471834 57286:57286 +0.00011266336187471834 55674:55674 +0.00011266336187471834 34182:34182 +0.00011266336187471834 58078:58078 +0.00011266336187471834 56821:56821 +0.00011266336187471834 33644:33644 +0.00011266336187471834 60755:60755 +0.00011266336187471834 59057:59057 +0.00011266336187471834 57310:57310 +0.00011266336187471834 56296:56296 +0.00011266336187471834 57539:57539 +0.00011266336187471834 56077:56077 +0.00011266336187471834 55639:55639 +0.00011266336187471834 58656:58656 +0.00011266336187471834 35372:35372 +0.00011266336187471834 58659:58659 +0.00011266336187471834 56622:56622 +0.00011266336187471834 58215:58215 +0.00011266336187471834 60223:60223 +0.00011266336187471834 60073:60073 +0.00011266336187471834 33796:33796 +0.00011266336187471834 58023:58023 +0.00011266336187471834 34309:34309 +0.00011266336187471834 33856:33856 +0.00011266336187471834 59773:59773 +0.00011266336187471834 59076:59076 +0.00011266336187471834 57014:57014 +0.00011266336187471834 60166:60166 +0.00011266336187471834 56758:56758 +0.00011266336187471834 34359:34359 +0.00011266336187471834 33815:33815 +0.00011266336187471834 33692:33692 +0.00011266336187471834 58606:58606 +0.00011266336187471834 60815:60815 +0.00011266336187471834 35459:35459 +0.00011266336187471834 35522:35522 +0.00011266336187471834 56248:56248 +0.00011266336187471834 56049:56049 +0.00011266336187471834 33636:33636 +0.00011266336187471834 33132:33132 +0.00011266336187471834 55899:55899 +0.00011266336187471834 55800:55800 +0.00011266336187471834 56475:56475 +0.00011266336187471834 59568:59568 +0.00011266336187471834 60674:60674 +0.00011266336187471834 33104:33104 +0.00011266336187471834 60801:60801 +0.00011266336187471834 59493:59493 +0.00011266336187471834 58297:58297 +0.00011266336187471834 59457:59457 +0.00011266336187471834 57676:57676 +0.00011266336187471834 34840:34840 +0.00011266336187471834 60690:60690 +0.00011266336187471834 32841:32841 +0.00011266336187471834 33311:33311 +0.00011266336187471834 34766:34766 +0.00011266336187471834 57229:57229 +0.00011266336187471834 35025:35025 +0.00011266336187471834 59512:59512 +0.00011266336187471834 57383:57383 +0.00011266336187471834 57071:57071 +0.00011266336187471834 56139:56139 +0.00011266336187471834 34031:34031 +0.00011266336187471834 57248:57248 +0.00011266336187471834 35027:35027 +0.00011266336187471834 34971:34971 +0.00011266336187471834 35491:35491 +0.00011266336187471834 58155:58155 +0.00011266336187471834 57020:57020 +0.00011266336187471834 58183:58183 +0.00011266336187471834 56698:56698 +0.00011266336187471834 35431:35431 +0.00011266336187471834 34858:34858 +0.00011266336187471834 56469:56469 +0.00011266336187471834 33756:33756 +0.00011266336187471834 33185:33185 +0.00011266336187471834 58137:58137 +0.00011266336187471834 55749:55749 +0.00011266336187471834 58770:58770 +0.00011266336187471834 57328:57328 +0.00011266336187471834 33407:33407 +0.00011266336187471834 60185:60185 +0.00011266336187471834 32882:32882 +0.00011266336187471834 55745:55745 +0.00011266336187471834 60356:60356 +0.00011266336187471834 60350:60350 +0.00011266336187471834 60578:60578 +0.00011266336187471834 58173:58173 +0.00011266336187471834 60573:60573 +0.00011266336187471834 59699:59699 +0.00011266336187471834 59327:59327 +0.00011266336187471834 58927:58927 +0.00011266336187471834 56418:56418 +0.00011266336187471834 55740:55740 +0.00011266336187471834 56318:56318 +0.00011266336187471834 34746:34746 +0.00011266336187471834 60856:60856 +0.00011266336187471834 56071:56071 +0.00011266336187471834 55853:55853 +0.00011266336187471834 59413:59413 +0.00011266336187471834 59805:59805 +0.00011266336187471834 57833:57833 +0.00011266336187471834 34564:34564 +0.00011266336187471834 59052:59052 +0.00011266336187471834 32804:32804 +0.00011266336187471834 55819:55819 +0.00011266336187471834 34052:34052 +0.00011266336187471834 56163:56163 +0.00011266336187471834 56061:56061 +0.00011266336187471834 58455:58455 +0.00011266336187471834 55866:55866 +0.00011266336187471834 58936:58936 +0.00011266336187471834 35028:35028 +0.00011266336187471834 57791:57791 +0.00011266336187471834 57427:57427 +0.00011266336187471834 57076:57076 +0.00011266336187471834 59110:59110 +0.00011266336187471834 35029:35029 +0.00011266336187471834 35531:35531 +0.00011266336187471834 33430:33430 +0.00011266336187471834 56654:56654 +0.00011266336187471834 56531:56531 +0.00011266336187471834 59209:59209 +0.00011266336187471834 34662:34662 +0.00011266336187471834 33702:33702 +0.00011266336187471834 33753:33753 +0.00011266336187471834 57750:57750 +0.00011266336187471834 33686:33686 +0.00011266336187471834 32799:32799 +0.00011266336187471834 58343:58343 +0.00011266336187471834 57641:57641 +0.00011266336187471834 33879:33879 +0.00011266336187471834 33072:33072 +0.00011266336187471834 60695:60695 +0.00011266336187471834 35358:35358 +0.00011266336187471834 60807:60807 +0.00011266336187471834 60751:60751 +0.00011266336187471834 59187:59187 +0.00011266336187471834 58513:58513 +0.00011266336187471834 59468:59468 +0.00011266336187471834 57517:57517 +0.00011266336187471834 56159:56159 +0.00011266336187471834 58636:58636 +0.00011266336187471834 56833:56833 +0.00011266336187471834 57590:57590 +0.00011266336187471834 55747:55747 +0.00011266336187471834 33077:33077 +0.00011266336187471834 55640:55640 +0.00011266336187471834 33452:33452 +0.00011266336187471834 57529:57529 +0.00011266336187471834 56570:56570 +0.00011266336187471834 59004:59004 +0.00011266336187471834 59732:59732 +0.00011266336187471834 56260:56260 +0.00011266336187471834 60677:60677 +0.00011266336187471834 57877:57877 +0.00011266336187471834 60081:60081 +0.00011266336187471834 56706:56706 +0.00011266336187471834 57662:57662 +0.00011266336187471834 56073:56073 +0.00011266336187471834 35224:35224 +0.00011266336187471834 33934:33934 +0.00011266336187471834 35259:35259 +0.00011266336187471834 60059:60059 +0.00011266336187471834 33399:33399 +0.00011266336187471834 56140:56140 +0.00011266336187471834 33816:33816 +0.00011266336187471834 60761:60761 +0.00011266336187471834 58407:58407 +0.00011266336187471834 56703:56703 +0.00011266336187471834 34610:34610 +0.00011266336187471834 60724:60724 +0.00011266336187471834 58664:58664 +0.00011266336187471834 35340:35340 +0.00011266336187471834 57376:57376 +0.00011266336187471834 58810:58810 +0.00011266336187471834 56227:56227 +0.00011266336187471834 33941:33941 +0.00011266336187471834 33257:33257 +0.00011266336187471834 59120:59120 +0.00011266336187471834 56099:56099 +0.00011266336187471834 56474:56474 +0.00011266336187471834 58737:58737 +0.00011266336187471834 58152:58152 +0.00011266336187471834 34462:34462 +0.00011266336187471834 33624:33624 +0.00011266336187471834 33495:33495 +0.00011266336187471834 56950:56950 +0.00011266336187471834 60978:60978 +0.00011266336187471834 60083:60083 +0.00011266336187471834 56574:56574 +0.00011266336187471834 60718:60718 +0.00011266336187471834 59603:59603 +0.00011266336187471834 57501:57501 +0.00011266336187471834 60485:60485 +0.00011266336187471834 59975:59975 +0.00011266336187471834 34994:34994 +0.00011266336187471834 34328:34328 +0.00011266336187471834 35347:35347 +0.00011266336187471834 59529:59529 +0.00011266336187471834 57300:57300 +0.00011266336187471834 59587:59587 +0.00011266336187471834 58641:58641 +0.00011266336187471834 35154:35154 +0.00011266336187471834 60332:60332 +0.00011266336187471834 32940:32940 +0.00011266336187471834 34452:34452 +0.00011266336187471834 59827:59827 +0.00011266336187471834 34351:34351 +0.00011266336187471834 33150:33150 +0.00011266336187471834 55962:55962 +0.00011266336187471834 34157:34157 +0.00011266336187471834 33918:33918 +0.00011266336187471834 58185:58185 +0.00011266336187471834 34854:34854 +0.00011266336187471834 34671:34671 +0.00011266336187471834 34397:34397 +0.00011266336187471834 34891:34891 +0.00011266336187471834 32868:32868 +0.00011266336187471834 57381:57381 +0.00011266336187471834 35138:35138 +0.00011266336187471834 58548:58548 +0.00011266336187471834 55958:55958 +0.00011266336187471834 60679:60679 +0.00011266336187471834 57468:57468 +0.00011266336187471834 56455:56455 +0.00011266336187471834 34604:34604 +0.00011266336187471834 58719:58719 +0.00011266336187471834 56987:56987 +0.00011266336187471834 55903:55903 +0.00011266336187471834 57909:57909 +0.00011266336187471834 57469:57469 +0.00011266336187471834 60651:60651 +0.00011266336187471834 59452:59452 +0.00011266336187471834 58669:58669 +0.00011266336187471834 56380:56380 +0.00011266336187471834 59652:59652 +0.00011266336187471834 58046:58046 +0.00011266336187471834 35371:35371 +0.00011266336187471834 59115:59115 +0.00011266336187471834 33398:33398 +0.00011266336187471834 58321:58321 +0.00011266336187471834 58261:58261 +0.00011266336187471834 58017:58017 +0.00011266336187471834 58091:58091 +0.00011266336187471834 60514:60514 +0.00011266336187471834 56716:56716 +0.00011266336187471834 56396:56396 +0.00011266336187471834 58639:58639 +0.00011266336187471834 33614:33614 +0.00011266336187471834 58486:58486 +0.00011266336187471834 35524:35524 +0.00011266336187471834 33148:33148 +0.00011266336187471834 57219:57219 +0.00011266336187471834 35140:35140 +0.00011266336187471834 33170:33170 +0.00011266336187471834 58625:58625 +0.00011266336187471834 35382:35382 +0.00011266336187471834 32793:32793 +0.00011266336187471834 59890:59890 +0.00011266336187471834 58143:58143 +0.00011266336187471834 56540:56540 +0.00011266336187471834 56254:56254 +0.00011266336187471834 58911:58911 +0.00011266336187471834 56272:56272 +0.00011266336187471834 59433:59433 +0.00011266336187471834 34027:34027 +0.00011266336187471834 58247:58247 +0.00011266336187471834 57319:57319 +0.00011266336187471834 56744:56744 +0.00011266336187471834 59714:59714 +0.00011266336187471834 58811:58811 +0.00011266336187471834 57951:57951 +0.00011266336187471834 33576:33576 +0.00011266336187471834 58987:58987 +0.00011266336187471834 33739:33739 +0.00011266336187471834 60691:60691 +0.00011266336187471834 33623:33623 +0.00011266336187471834 34998:34998 +0.00011266336187471834 59813:59813 +0.00011266336187471834 57429:57429 +0.00011266336187471834 32971:32971 +0.00011266336187471834 59215:59215 +0.00011266336187471834 33358:33358 +0.00011266336187471834 35194:35194 +0.00011266336187471834 59171:59171 +0.00011266336187471834 58951:58951 +0.00011266336187471834 32771:32771 +0.00011266336187471834 57355:57355 +0.00011266336187471834 35212:35212 +0.00011266336187471834 34530:34530 +0.00011266336187471834 32792:32792 +0.00011266336187471834 33970:33970 +0.00011266336187471834 59706:59706 +0.00011266336187471834 57105:57105 +0.00011266336187471834 56877:56877 +0.00011266336187471834 56481:56481 +0.00011266336187471834 56723:56723 +0.00011266336187471834 57367:57367 +0.00011266336187471834 56575:56575 +0.00011266336187471834 35238:35238 +0.00011266336187471834 59663:59663 +0.00011266336187471834 34821:34821 +0.00011266336187471834 60363:60363 +0.00011266336187471834 60230:60230 +0.00011266336187471834 59395:59395 +0.00011266336187471834 35010:35010 +0.00011266336187471834 59891:59891 +0.00011266336187471834 33500:33500 +0.00011266336187471834 33640:33640 +0.00011266336187471834 59701:59701 +0.00011266336187471834 59867:59867 +0.00011266336187471834 59648:59648 +0.00011266336187471834 56780:56780 +0.00011266336187471834 58195:58195 +0.00011266336187471834 58775:58775 +0.00011266336187471834 59003:59003 +0.00011266336187471834 33709:33709 +0.00011266336187471834 60905:60905 +0.00011266336187471834 56456:56456 +0.00011266336187471834 34758:34758 +0.00011266336187471834 34715:34715 +0.00011266336187471834 56161:56161 +0.00011266336187471834 59830:59830 +0.00011266336187471834 55622:55622 +0.00011266336187471834 32895:32895 +0.00011266336187471834 57322:57322 +0.00011266336187471834 33642:33642 +0.00011266336187471834 56773:56773 +0.00011266336187471834 57887:57887 +0.00011266336187471834 55743:55743 +0.00011266336187471834 60949:60949 +0.00011266336187471834 56702:56702 +0.00011266336187471834 58692:58692 +0.00011266336187471834 33637:33637 +0.00011266336187471834 56674:56674 +0.00011266336187471834 60085:60085 +0.00011266336187471834 59697:59697 +0.00011266336187471834 58723:58723 +0.00011266336187471834 58405:58405 +0.00011266336187471834 57195:57195 +0.00011266336187471834 33950:33950 +0.00011266336187471834 34225:34225 +0.00011266336187471834 33653:33653 +0.00011266336187471834 58847:58847 +0.00011266336187471834 58959:58959 +0.00011266336187471834 57983:57983 +0.00011266336187471834 33622:33622 +0.00011266336187471834 60681:60681 +0.00011266336187471834 33616:33616 +0.00011266336187471834 56397:56397 +0.00011266336187471834 33982:33982 +0.00011266336187471834 34565:34565 +0.00011266336187471834 33058:33058 +0.00011266336187471834 58853:58853 +0.00011266336187471834 58721:58721 +0.00011266336187471834 33173:33173 +0.00011266336187471834 57842:57842 +0.00011266336187471834 35379:35379 +0.00011266336187471834 60906:60906 +0.00011266336187471834 56134:56134 +0.00011266336187471834 55814:55814 +0.00011266336187471834 35233:35233 +0.00011266336187471834 35005:35005 +0.00011266336187471834 34312:34312 +0.00011266336187471834 35436:35436 +0.00011266336187471834 59657:59657 +0.00011266336187471834 59143:59143 +0.00011266336187471834 60109:60109 +0.00011266336187471834 58312:58312 +0.00011266336187471834 33200:33200 +0.00011266336187471834 56069:56069 +0.00011266336187471834 59342:59342 +0.00011266336187471834 56075:56075 +0.00011266336187471834 34202:34202 +0.00011266336187471834 34104:34104 +0.00011266336187471834 58614:58614 +0.00011266336187471834 55775:55775 +0.00011266336187471834 33707:33707 +0.00011266336187471834 33703:33703 +0.00011266336187471834 57959:57959 +0.00011266336187471834 34787:34787 +0.00011266336187471834 55753:55753 +0.00011266336187471834 34086:34086 +0.00011266336187471834 59250:59250 +0.00011266336187471834 60196:60196 +0.00011266336187471834 57470:57470 +0.00011266336187471834 55844:55844 +0.00011266336187471834 57046:57046 +0.00011266336187471834 59809:59809 +0.00011266336187471834 58948:58948 +0.00011266336187471834 33834:33834 +0.00011266336187471834 57876:57876 +0.00011266336187471834 34012:34012 +0.00011266336187471834 59723:59723 +0.00011266336187471834 59530:59530 +0.00011266336187471834 60106:60106 +0.00011266336187471834 58044:58044 +0.00011266336187471834 55620:55620 +0.00011266336187471834 34129:34129 +0.00011266336187471834 56913:56913 +0.00011266336187471834 56527:56527 +0.00011266336187471834 35181:35181 +0.00011266336187471834 34473:34473 +0.00011266336187471834 55679:55679 +0.00011266336187471834 35144:35144 +0.00011266336187471834 33833:33833 +0.00011266336187471834 33222:33222 +0.00011266336187471834 34450:34450 +0.00011266336187471834 59434:59434 +0.00011266336187471834 55712:55712 +0.00011266336187471834 60862:60862 +0.00011266336187471834 55697:55697 +0.00011266336187471834 35199:35199 +0.00011266336187471834 59979:59979 +0.00011266336187471834 34625:34625 +0.00011266336187471834 58146:58146 +0.00011266336187471834 34345:34345 +0.00011266336187471834 58774:58774 +0.00011266336187471834 58681:58681 +0.00011266336187471834 56310:56310 +0.00011266336187471834 34319:34319 +0.00011266336187471834 58480:58480 +0.00011266336187471834 60440:60440 +0.00011266336187471834 56320:56320 +0.00011266336187471834 55654:55654 +0.00011266336187471834 56056:56056 +0.00011266336187471834 58858:58858 +0.00011266336187471834 58223:58223 +0.00011266336187471834 60790:60790 +0.00011266336187471834 58526:58526 +0.00011266336187471834 33224:33224 +0.00011266336187471834 56643:56643 +0.00011266336187471834 55839:55839 +0.00011266336187471834 56238:56238 +0.00011266336187471834 57678:57678 +0.00011266336187471834 56124:56124 +0.00011266336187471834 35255:35255 +0.00011266336187471834 56218:56218 +0.00011266336187471834 33891:33891 +0.00011266336187471834 58369:58369 +0.00011266336187471834 57032:57032 +0.00011266336187471834 56080:56080 +0.00011266336187471834 55956:55956 +0.00011266336187471834 33248:33248 +0.00011266336187471834 60701:60701 +0.00011266336187471834 58300:58300 +0.00011266336187471834 59554:59554 +0.00011266336187471834 58132:58132 +0.00011266336187471834 35388:35388 +0.00011266336187471834 60303:60303 +0.00011266336187471834 58158:58158 +0.00011266336187471834 60645:60645 +0.00011266336187471834 33362:33362 +0.00011266336187471834 59543:59543 +0.00011266336187471834 58292:58292 +0.00011266336187471834 59388:59388 +0.00011266336187471834 56442:56442 +0.00011266336187471834 32878:32878 +0.00011266336187471834 35223:35223 +0.00011266336187471834 58819:58819 +0.00011266336187471834 58136:58136 +0.00011266336187471834 33939:33939 +0.00011266336187471834 34372:34372 +0.00011266336187471834 58176:58176 +0.00011266336187471834 58019:58019 +0.00011266336187471834 55737:55737 +0.00011266336187471834 60024:60024 +0.00011266336187471834 56336:56336 +0.00011266336187471834 33326:33326 +0.00011266336187471834 56591:56591 +0.00011266336187471834 34810:34810 +0.00011266336187471834 59007:59007 +0.00011266336187471834 59609:59609 +0.00011266336187471834 58760:58760 +0.00011266336187471834 57917:57917 +0.00011266336187471834 58218:58218 +0.00011266336187471834 33272:33272 +0.00011266336187471834 34231:34231 +0.00011266336187471834 58374:58374 +0.00011266336187471834 33656:33656 +0.00011266336187471834 35497:35497 +0.00011266336187471834 57483:57483 +0.00011266336187471834 32908:32908 +0.00011266336187471834 59183:59183 +0.00011266336187471834 57818:57818 +0.00011266336187471834 33878:33878 +0.00011266336187471834 33003:33003 +0.00011266336187471834 57091:57091 +0.00011266336187471834 60795:60795 +0.00011266336187471834 59695:59695 +0.00011266336187471834 56155:56155 +0.00011266336187471834 55665:55665 +0.00011266336187471834 33922:33922 +0.00011266336187471834 60466:60466 +0.00011266336187471834 34463:34463 +0.00011266336187471834 60243:60243 +0.00011266336187471834 58411:58411 +0.00011266336187471834 56656:56656 +0.00011266336187471834 34996:34996 +0.00011266336187471834 58362:58362 +0.00011266336187471834 35471:35471 +0.00011266336187471834 33357:33357 +0.00011266336187471834 57728:57728 +0.00011266336187471834 57516:57516 +0.00011266336187471834 34920:34920 +0.00011266336187471834 33931:33931 +0.00011266336187471834 33481:33481 +0.00011266336187471834 60417:60417 +0.00011266336187471834 57552:57552 +0.00011266336187471834 33863:33863 +0.00011266336187471834 60241:60241 +0.00011266336187471834 33465:33465 +0.00011266336187471834 58144:58144 +0.00011266336187471834 35415:35415 +0.00011266336187471834 33798:33798 +0.00011266336187471834 58425:58425 +0.00011266336187471834 33127:33127 +0.00011266336187471834 33078:33078 +0.00011266336187471834 33526:33526 +0.00011266336187471834 59887:59887 +0.00011266336187471834 58751:58751 +0.00011266336187471834 57946:57946 +0.00011266336187471834 57245:57245 +0.00011266336187471834 33681:33681 +0.00011266336187471834 59476:59476 +0.00011266336187471834 59362:59362 +# +-wc_wc +64,0.9984116479152879 32,1.0 +40,0.00026472534745201854 32,1.0 +55,0.00026472534745201854 23,1.0 +56,0.00026472534745201854 24,1.0 +62,0.00026472534745201854 30,1.0 +36,0.00026472534745201854 4,1.0 +52,0.00026472534745201854 20,1.0 +# +-wc_hi +# +-hi_wc +# +-hi_hi +# +-wc_lo +# +-lo_wc +# +-hi_lo +# +-lo_hi +# +-lo_lo +# +-wc_ar +# +-ar_wc +# +-hi_ar +# +-ar_hi +# +-wc_em +64,1.0 32,1.0 +# +-em_wc +# +-hi_em +# +-em_hi +# +-lo_ar +# +-ar_lo +# +-lo_em +# +-em_lo +# +-ar_ar +# +-ar_em +# +-em_ar +# +-em_em +64,1.0 32,1.0 +# +-snest +1 +# +-sskew +0 0.0 1.0 0.9889719219328158 +1 0.0 1.0 0.6585888077858881 +2 0.0 1.0 0.997082494498179 +3 0.75 0.25 0.9998044009779951 +4 0.8 0.2 0.961823535384303 +5 0.8333333333333334 0.16666666666666666 0.9978632478632479 +6 0.7142857142857143 0.2857142857142857 0.9098166127292342 +7 0.8888888888888888 0.1111111111111111 0.0 +8 0.7777777777777778 0.2222222222222222 0.9365384615384615 +9 0.7272727272727273 0.2727272727272727 0.957197856439339 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 0.9285714285714286 0.07142857142857142 0.5 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 1.0 0.0 0.0 +17 0.9333333333333333 0.06666666666666667 0.9958847736625515 +18 0.8125 0.1875 0.24325092355782893 +19 0.7894736842105263 0.21052631578947367 0.7117055334830427 +20 1.0 0.0 0.0 +21 0.8260869565217391 0.17391304347826086 0.6953227931488801 +22 0.7037037037037037 0.2962962962962963 0.5713022165387894 +23 0.6571428571428571 0.34285714285714286 0.4480738059721748 +24 0.6595744680851063 0.3404255319148936 0.2589909102924567 +25 0.5166666666666667 0.48333333333333334 0.2002120733636143 +26 0.550561797752809 0.449438202247191 0.1436688471727894 +27 0.5193798449612403 0.4806201550387597 0.10299577214899797 +28 0.20512820512820512 0.7948717948717948 0.39740355852410186 +29 0.2857142857142857 0.7142857142857143 0.34246536796536803 +30 0.5333333333333333 0.4666666666666667 0.19494047619047622 +31 0.6742857142857143 0.32571428571428573 0.08646616541353384 +32 0.0 0.0 0.0 +# +-dnest +2 +# +-dskew +0 0.0 1.0 0.7320334742472607 +1 0.0 1.0 0.6482798833819242 +2 0.5 0.5 0.99867197875166 +3 0.6666666666666666 0.3333333333333333 0.0 +4 0.6666666666666666 0.3333333333333333 0.9990661841951675 +5 0.75 0.25 0.996720927509076 +6 0.8 0.2 0.9678472138281156 +7 1.0 0.0 0.0 +8 0.8333333333333334 0.16666666666666666 0.999516265570202 +9 0.8571428571428571 0.14285714285714285 0.9990315942379857 +10 1.0 0.0 0.0 +11 1.0 0.0 0.0 +12 1.0 0.0 0.0 +13 1.0 0.0 0.0 +14 1.0 0.0 0.0 +15 1.0 0.0 0.0 +16 0.875 0.125 0.696078431372549 +17 0.6666666666666666 0.3333333333333333 0.5857400547902921 +18 0.5 0.5 0.4346560846560847 +19 0.5555555555555556 0.4444444444444444 0.5687523342670401 +20 0.56 0.44 0.4505772005772006 +21 0.7777777777777778 0.2222222222222222 0.5625000000000001 +22 0.8636363636363636 0.13636363636363635 0.5474747474747474 +23 0.82 0.18 0.37029089175011926 +24 0.864406779661017 0.13559322033898305 0.2604166666666667 +25 0.8955223880597015 0.1044776119402985 0.16666666666666669 +26 0.8648648648648649 0.13513513513513514 0.316523400191022 +27 0.9285714285714286 0.07142857142857142 0.2456140350877193 +28 1.0 0.0 0.0 +29 1.0 0.0 0.0 +30 0.8888888888888888 0.1111111111111111 0.5 +31 1.0 0.0 0.0 +32 0.0 0.0 0.0 +# +-pcorr +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +# +-openflow +--- +in_port: + '37': 2 + '108': 2 + '311': 2 + '33': 2 + '41': 2 + '29': 2 + '134': 2 + '486': 2 + '91': 2 + '117': 2 + '61': 2 + '23': 2 + '106': 2 + '5': 2 + '49': 2 + '54': 2 + '107': 2 + '129': 2 + '81': 2 + '209': 2 + '42': 2 + '310': 2 + '37554': 1 + '37698': 1 + '37584': 1 + '37653': 1 + '37669': 1 + '37553': 1 + '37612': 1 + '37599': 1 + '37702': 1 + '37715': 1 + '37607': 1 + '37660': 1 + '37598': 1 + '37603': 1 + '37703': 1 + '37670': 1 + '37640': 1 + '37696': 1 + '37597': 1 + '36736': 1 + '37737': 1 + '37697': 1 + '37621': 1 + '37701': 1 + '37735': 1 + '37699': 1 + '37562': 1 + '37588': 1 + '37658': 1 + '37617': 1 + '36697': 1 + '37590': 1 + '37586': 1 + '37555': 1 + '37716': 1 + '37712': 1 + '37611': 1 + '37561': 1 + '37663': 1 + '37714': 1 + '37604': 1 + '36666': 1 + '36464': 1 + '37606': 1 + '37605': 1 + '37681': 1 + '37671': 1 + '37616': 1 + '37645': 1 + '36662': 1 + '37725': 1 + '37700': 1 + '36717': 1 + '36803': 1 + '37710': 1 + '37587': 1 + '37544': 1 + '37659': 1 + '37721': 1 + '37685': 1 + '37602': 1 + '36369': 1 + '37579': 1 + '37600': 1 + '37667': 1 + '37614': 1 + '37281': 1 + '37648': 1 + '37549': 1 + '37679': 1 + '37678': 1 + '37736': 1 + '37662': 1 + '37622': 1 + '37665': 1 + '36646': 1 + '37720': 1 + '37722': 1 + '37655': 1 + '37713': 1 + '37717': 1 + '37649': 1 + '37686': 1 + '37727': 1 + '37563': 1 + '37738': 1 + '37080': 1 + '37682': 1 + '37550': 1 + '37552': 1 + '37583': 1 + '37675': 1 + '37709': 1 + '36361': 1 + '37613': 1 + '37551': 1 + '37684': 1 + '37656': 1 + '37547': 1 + '36658': 1 + '37277': 1 + '37545': 1 + '36786': 1 + '37601': 1 + '37580': 1 + '37282': 1 + '37657': 1 + '37565': 1 + '37543': 1 + '37084': 1 + '37546': 1 + '37743': 1 + '37585': 1 + '37693': 1 + '37556': 1 + '37683': 1 + '37689': 1 + '37688': 1 +eth_type: + '0x800': 4774 +dl_src: + fa:16:3e: 235 +dl_dst: + 01:80:c2: 1 + 01:00:0c: 4 + 00:e0:2b: 3 + fa:16:3e: 15619 + ff:ff:ff: 12 + '01:00:00': 74 + c2:81:09: 16 + '00:50:56': 1 + '00:00:00': 4 +unique_vlan_ids_count: 0 +empty_rules_count: 3890 +rule_distribution: +- attributes: + - dl_dst + count: 1331 +- attributes: + - in_port + count: 162 +- attributes: + - dl_dst + - nw_dst + count: 88 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - tp_dst + count: 528 +- attributes: + - nw_src + count: 6 +- attributes: + - nw_dst + - tp_dst + - tp_src + count: 137 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + - nw_src + count: 4170 +- attributes: + - nw_dst + count: 157 +- attributes: + - dl_dst + - eth_type + - nw_dst + - nw_proto + count: 16 +- attributes: + - dl_dst + - nw_dst + - tp_dst + - tp_src + count: 20 +- attributes: + - dl_dst + - nw_dst + - nw_src + count: 1390 +- attributes: + - dl_src + count: 57 +- attributes: + - dl_src + - nw_src + count: 118 +- attributes: + - dl_src + - eth_type + - nw_proto + - nw_src + count: 60 +- attributes: + - dl_dst + - nw_dst + - nw_src + - tp_dst + - tp_src + count: 8191 +# diff --git a/vendor/Makefile b/vendor/Makefile index 17217dd..5f59624 100644 --- a/vendor/Makefile +++ b/vendor/Makefile @@ -1,22 +1,42 @@ # Compilation of classbench +# Potential backup time +BACKUP_TIME=$(shell date --rfc-3339=seconds | tr ' ' '_') + all: compile download: - # Make backup of db_generator if exists - -[ -d db_generator ] && mv db_generator db_generator-$(shell date --rfc-3339=seconds | tr ' ' '_') + # Make backup of db_generator, if exists + -[ -d db_generator ] && mv db_generator db_generator-$(BACKUP_TIME) # Download and unpack ClassBench - wget -O- -q http://www.arl.wustl.edu/classbench/db_generator.tar.gz | tar -xvz + wget -O- --no-check-certificate -q http://www.arl.wustl.edu/classbench/db_generator.tar.gz | tar -xvz + + # Make backup of parameter_files, if exists + -[ -d parameter_files ] && mv parameter_files parameter_files-$(BACKUP_TIME) + + # Download and unpack ClassBench parameter files + wget -O- --no-check-certificate -q http://www.arl.wustl.edu/classbench/parameter_files.tar.gz | tar -xvz patch: download # Apply patches from ../patches - git apply --directory=vendor/db_generator ../patches/ipv6.patch + git apply --directory=db_generator ../patches/improvements_ipv6.patch + #git apply --directory=db_generator ../patches/ipv6.patch + #git apply --directory=db_generator ../patches/improvements.patch -compile: patch # Patching PortList (extension of preallocated array is necessary) # Raise limit of L5 rules from 200 to 20000. sed -i 's/200/20000/' db_generator/PortList.h + # solve bug for stack corruption in Ubuntu 17.04 + sed -i 's/comm\[[0-9]\]/comm\[7\]/g' db_generator/*.cc + # Define return type for original ClassBench's main function + sed -i 's/main/int main/' db_generator/db_generator.cc + # Replace Null (i.e., integer constant equal to 0) with NULL (i.e., null pointer) + sed -i 's/Null/NULL/' db_generator/FlagList.cc db_generator/custom_db.cc +compile: patch # Recurse to ClassBench compilation make -C db_generator -B db_generator + +clean: + rm -rf db_generator* parameter_files*